Compare commits

...

7 Commits

94
Cargo.lock generated

@ -2889,11 +2889,11 @@ dependencies = [
[[package]]
name = "matchers"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata 0.1.10",
"regex-automata",
]
[[package]]
@ -2988,7 +2988,7 @@ dependencies = [
"naga",
"once_cell",
"regex",
"regex-syntax 0.8.5",
"regex-syntax",
"rustc-hash 1.1.0",
"thiserror 1.0.69",
"tracing",
@ -3127,12 +3127,11 @@ dependencies = [
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
version = "0.50.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
dependencies = [
"overload",
"winapi",
"windows-sys 0.52.0",
]
[[package]]
@ -3504,12 +3503,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owned_ttf_parser"
version = "0.25.0"
@ -4000,17 +3993,8 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
"regex-automata",
"regex-syntax",
]
[[package]]
@ -4021,15 +4005,9 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.5",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.5"
@ -4472,7 +4450,7 @@ dependencies = [
"memchr",
"ntapi",
"objc2-core-foundation",
"windows 0.57.0",
"windows 0.54.0",
]
[[package]]
@ -4662,14 +4640,14 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.19"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
@ -5211,16 +5189,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.58.0"
@ -5263,18 +5231,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.58.0"
@ -5312,17 +5268,6 @@ dependencies = [
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-implement"
version = "0.58.0"
@ -5345,17 +5290,6 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.58.0"

@ -3,6 +3,17 @@ name = "games"
version = "0.1.0"
edition = "2024"
[[example]]
name = "demo_parallax2d"
path = "examples/demos/parallax2d.rs"
[[example]]
name = "demo_parallax3d"
path = "examples/demos/parallax3d.rs"
[features]
hide_debug = []
[dependencies]
thiserror = "2.0.12"

@ -1,2 +0,0 @@
* setup CI template in web server running on port 8000
* setup mock bevy app running on port 8001 w/ first app running in iframe

@ -0,0 +1,104 @@
use bevy::{color::palettes::css::*, prelude::*};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(ClearColor(WHITE.into()))
.add_event::<CameraMovement>()
.add_systems(Startup, setup_2d)
.add_systems(Update, (move_camera, track_camera_movement, parallax))
.run();
}
#[derive(Component)]
struct ParallaxDistance(f32);
fn setup_2d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn((
Camera2d,
AmbientLight {
brightness: 160.0,
..default()
},
));
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(100.0, 100.0))),
MeshMaterial2d(materials.add(Color::from(RED))),
Transform::from_xyz(0.0, 0.0, -1.0),
ParallaxDistance(1.0),
children![(
Text2d::new("Parallax Distance: 1"),
TextColor(BLACK.into()),
Transform::from_xyz(150.0, 50.0, 0.0)
)],
));
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(100.0, 100.0))),
MeshMaterial2d(materials.add(Color::from(GREEN))),
Transform::from_xyz(0.0, 0.0, -5.0),
ParallaxDistance(5.0),
children![(
Text2d::new("Parallax Distance: 5"),
TextColor(BLACK.into()),
Transform::from_xyz(150.0, 0.0, 0.0)
)],
));
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(100.0, 100.0))),
MeshMaterial2d(materials.add(Color::from(BLUE))),
Transform::from_xyz(0.0, 0.0, -10.0),
ParallaxDistance(10.0),
children![(
Text2d::new("Parallax Distance: 10"),
TextColor(BLACK.into()),
Transform::from_xyz(150.0, -50.0, 0.0)
)],
));
}
fn move_camera(keys: Res<ButtonInput<KeyCode>>, mut camera: Single<&mut Transform, With<Camera>>) {
const SPEED: f32 = 5.0;
if keys.pressed(KeyCode::ArrowLeft) {
camera.translation.x += SPEED;
} else if keys.pressed(KeyCode::ArrowRight) {
camera.translation.x -= SPEED;
}
if keys.pressed(KeyCode::ArrowUp) {
camera.translation.y -= SPEED;
} else if keys.pressed(KeyCode::ArrowDown) {
camera.translation.y += SPEED;
}
}
#[derive(Event)]
struct CameraMovement(Vec3);
fn track_camera_movement(
mut events: EventWriter<CameraMovement>,
camera: Query<&Transform, (With<Camera>, Changed<Transform>)>,
mut last: Local<Vec3>,
) {
camera.iter().for_each(|Transform { translation, .. }| {
events.write(CameraMovement(*last - *translation));
*last = *translation;
});
}
fn parallax(
mut events: EventReader<CameraMovement>,
mut query: Query<(&mut Transform, &ParallaxDistance)>,
) {
events.read().for_each(|CameraMovement(v)| {
query.iter_mut().for_each(|(mut t, ParallaxDistance(d))| {
t.translation -= v / (20.0 / d);
});
});
}

@ -0,0 +1,138 @@
use bevy::{color::palettes::css::*, prelude::*};
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
resolution: (640.0, 480.0).into(),
..default()
}),
..default()
}))
.insert_resource(ClearColor(WHITE.into()))
.add_systems(Startup, setup_3d)
.add_systems(Update, (move_camera_buttons, button_color))
.run();
}
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Camera::default(),
Camera3d::default(),
AmbientLight {
brightness: 1280.0,
..default()
},
));
commands.spawn((
Mesh3d(meshes.add(Cuboid::default())),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: RED.into(),
..Default::default()
})),
Transform::from_xyz(0.0, 0.0, -5.0),
));
commands.spawn((
Mesh3d(meshes.add(Cuboid::default())),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: GREEN.into(),
..Default::default()
})),
Transform::from_xyz(0.0, 0.0, -10.0),
));
commands.spawn((
Mesh3d(meshes.add(Cuboid::default())),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: BLUE.into(),
..Default::default()
})),
Transform::from_xyz(0.0, 0.0, -20.0),
));
commands
.spawn(Node {
align_self: AlignSelf::End,
justify_self: JustifySelf::Center,
..default()
})
.with_children(|parent| {
parent.spawn((
Node {
padding: UiRect::all(Val::Px(20.0)),
margin: UiRect::all(Val::Px(10.0)),
..default()
},
Button,
children![
Text::new("<-"),
Node {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
},
],
Movement(0.1),
BackgroundColor(ORANGE.into()),
));
parent.spawn((
Node {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
},
Text::new("movement"),
TextColor(BLACK.into()),
));
parent.spawn((
Node {
padding: UiRect::all(Val::Px(20.0)),
margin: UiRect::all(Val::Px(10.0)),
..default()
},
Button,
children![
Text::new("->"),
Node {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
},
],
Movement(-0.1),
BackgroundColor(ORANGE.into()),
));
});
}
fn button_color(
mut query: Query<(&Interaction, &mut BackgroundColor), (Changed<Interaction>, With<Button>)>,
) {
query.iter_mut().for_each(|(i, mut bg)| {
bg.0 = match i {
Interaction::None => ORANGE.into(),
Interaction::Hovered => ORANGE_RED.into(),
Interaction::Pressed => RED.into(),
};
});
}
#[derive(Component)]
struct Movement(f32);
fn move_camera_buttons(
query: Query<(&Interaction, &Movement), With<Button>>,
mut camera: Single<&mut Transform, With<Camera>>,
) {
query.iter().for_each(|(i, m)| {
if let (Interaction::Pressed, Movement(speed)) = (i, m) {
camera.translation.x += speed;
}
});
}

@ -0,0 +1,155 @@
use avian3d::math::Vector;
// TEMP
use avian2d::prelude::*;
use bevy::{color::palettes::css::*, prelude::*};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(PhysicsPlugins::default())
.insert_resource(ClearColor(WHITE.into()))
.add_systems(Startup, setup)
.add_systems(Update, move_player)
.add_systems(Update, follow_player)
.add_systems(Update, draw_gizmos)
.add_systems(
Update,
event_detection.run_if(on_event::<CollisionStarted>.or(on_event::<CollisionEnded>)),
)
.add_observer(set_tree_position)
.run();
}
#[derive(Component)]
struct Player;
#[derive(Component)]
struct RenderGizmo;
#[derive(Component)]
struct PlayArea;
#[derive(Component, Debug)]
struct TreePos(isize);
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(Camera2d);
// Spawn "trees" (which are also sensors)
[
("TREE -3", -3),
("TREE -2", -2),
("TREE -2", -1),
("TREE 1", 1),
("TREE 2", 2),
("TREE 3", 3),
]
.iter()
.for_each(|(label, pos)| {
commands.spawn((
RigidBody::Static,
Collider::rectangle(100.0, 250.0),
Mesh2d(meshes.add(Rectangle::new(100.0, 250.0))),
MeshMaterial2d(materials.add(Color::from(GREEN))),
TreePos(*pos),
children![Text2d::new(*label),],
));
});
commands.spawn((
Player,
RigidBody::Kinematic,
ExternalImpulse::default().with_persistence(true),
Collider::rectangle(50.0, 50.0),
Mesh2d(meshes.add(Rectangle::new(50.0, 50.0))),
MeshMaterial2d(materials.add(Color::from(RED))),
children![
(
Text2d::new("PLAYER"),
Transform::from_scale(Vec3::new(0.5, 0.5, 0.5)),
),
(
Text2d::new("PLAY AREA"),
Transform::from_xyz(0.0, 212.0, 1.0),
TextColor(BLACK.into())
),
(
RenderGizmo,
PlayArea,
Visibility::Visible,
Transform::from_scale(Vec3::new(400.0, 400.0, 0.0)),
),
],
));
}
fn set_tree_position(
trigger: Trigger<OnAdd, TreePos>,
tree_pos: Query<&TreePos>,
mut commands: Commands,
) {
let TreePos(pos) = tree_pos.get(trigger.target()).unwrap();
let x = if (*pos) > 0 {
(200.0 * (*pos) as f32) - 100.0
} else {
(200.0 * (*pos) as f32) + 100.0
};
let t = Transform::from_xyz(x, 0.0, 0.0);
commands.entity(trigger.target()).insert(t);
}
fn move_player(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut player: Single<&mut ExternalImpulse, With<Player>>,
) {
const SPEED: f32 = 5.0;
if keyboard_input.pressed(KeyCode::ArrowLeft) {
player.set_impulse(Vec2::NEG_X * SPEED);
} else if keyboard_input.pressed(KeyCode::ArrowRight) {
player.set_impulse(Vec2::X * SPEED);
}
}
fn follow_player(
player: Query<&Transform, (With<Player>, Changed<Transform>)>,
mut camera: Single<&mut Transform, (With<Camera2d>, Without<Player>)>,
) {
player.iter().for_each(|pt| {
camera.translation = pt.translation;
});
}
fn draw_gizmos(mut gizmos: Gizmos, play_area: Single<&GlobalTransform, With<RenderGizmo>>) {
gizmos.rect_2d(
play_area.translation().truncate(),
play_area.scale().truncate(),
MAGENTA,
)
}
fn event_detection(
mut start_events: EventReader<CollisionStarted>,
mut end_events: EventReader<CollisionEnded>,
player: Single<&Player>,
trees: Query<&TreePos>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
debug_assert!(!(start_events.is_empty() && end_events.is_empty()));
let s = start_events.read().map(|CollisionStarted(a, b)| (a, b));
let e = end_events.read().map(|CollisionEnded(a, b)| (a, b));
let mut events = s.chain(e);
let current_tree = events.find_map(|(a, b)| {
info!("{a:?}, {b:?}");
trees.get(*a).or(trees.get(*b)).ok()
});
info!("{:?}", current_tree);
if keyboard_input.pressed(KeyCode::ArrowLeft) {
// moving left
} else if keyboard_input.pressed(KeyCode::ArrowRight) {
// moving right
}
}

@ -19,14 +19,20 @@ optimize NAME:
# Replace old bin with new (compressed) bin
mv ./dist/{{NAME}}/bin_bg-tmp.wasm ./dist/{{NAME}}/bin_bg.wasm
build-example EXAMPLE:
build-example-dev EXAMPLE:
cargo build --example {{EXAMPLE}} --profile wasm-dev --target wasm32-unknown-unknown
build-example EXAMPLE:
cargo build --example {{EXAMPLE}} --profile release --target wasm32-unknown-unknown
build-bin GAME:
# wasm binary
cargo build --bin {{GAME}} --profile wasm-release --target wasm32-unknown-unknown
cargo build --bin {{GAME}} --profile wasm-release --target wasm32-unknown-unknown --features hide_debug
example-dev NAME: (build-example-dev NAME) (bindgen "wasm-dev" "examples"/NAME)
cp web/example.html ./dist/examples/{{NAME}}/index.html
example NAME: (build-example NAME) (bindgen "wasm-dev" "examples"/NAME)
example NAME: (build-example NAME) (bindgen "release" "examples"/NAME)
cp web/example.html ./dist/examples/{{NAME}}/index.html
# Build the web version

@ -30,6 +30,7 @@ impl Plugin for BaseGamePlugin {
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
title: self.title.clone(),
fit_canvas_to_parent: true,
resolution: self.target_resolution.clone(),
..default()
@ -47,8 +48,6 @@ impl Plugin for BaseGamePlugin {
.add_plugins(LoadingPlugin)
.add_plugins(BaseUiPlugin)
.add_plugins(ParallaxPlugin)
// .add_systems(Update, scale_game.run_if(any_component_changed::<Window>))
.insert_resource(TargetResolution(self.target_resolution.clone()))
.init_resource::<Rand>();
match self.game_type {
@ -58,9 +57,6 @@ impl Plugin for BaseGamePlugin {
}
}
#[derive(Resource)]
struct TargetResolution(WindowResolution);
/// System to toggle the visibility of entities based on their state
pub fn toggle_state_visibility<S: States + Component>(
mut q: Query<(Entity, &mut Visibility, &S)>,
@ -83,6 +79,7 @@ pub fn create_camera_3d(mut commands: Commands) {
Camera3d { ..default() },
Camera { ..default() },
AmbientLight::default(),
Transform::default(),
));
}
@ -94,22 +91,3 @@ pub fn create_camera_2d(mut commands: Commands) {
#[derive(Default, Resource)]
pub struct Rand(pub RandomState);
/// Scale the game based on the difference between the target and real resolution
fn scale_game(
mut window: Single<&mut Window>,
target_resolution: Res<TargetResolution>,
mut last_scale_factor: Local<f32>,
) {
let current_resolution: Vec2 = window.resolution.size();
let scale_width = current_resolution.x.round() / target_resolution.0.width().round();
let scale_height = current_resolution.y.round() / target_resolution.0.height().round();
let scale_factor = f32::min(scale_width, scale_height);
if window.resolution.scale_factor() != scale_factor {
// Need to check the previously set scale factor because the system can flip-flop otherwise
if scale_factor != *last_scale_factor {
*last_scale_factor = window.resolution.scale_factor();
window.resolution.set_scale_factor(scale_factor);
}
}
}

@ -326,7 +326,7 @@ fn populate_ground(
Name::new("ground"),
RigidBody::Static,
Collider::rectangle(1.0, 0.75),
Transform::from_xyz(100.0 * (*idx) as f32, -275.0, -1.0).with_scale(Vec3::splat(100.0)),
Transform::from_xyz(100.0 * (*idx) as f32, -275.0, -1.0).with_scale(Vec3::splat(106.0)),
));
}
@ -1279,7 +1279,9 @@ fn shimmer_button<T: Component>(mut bg: Single<&mut BackgroundColor, With<T>>, t
let chroma = 0.5;
let hue = (t * 60.0) % 360.0;
bg.0 = Oklcha {
lightness, chroma, hue,
lightness,
chroma,
hue,
alpha: bg.0.alpha(),
}
.into();

@ -0,0 +1,7 @@
# Falling Blocks RPG
This game is inspired by both Tetris and Peglin.
Your goal is to play Tetris (or a similar falling block game) but while that is happening you are carrying out a 2d real-time combat RPG battle.
Between battles/levels you choose a different level to go to in an overworld, choose upgrades, perks, and maybe some other stuff!

@ -3,8 +3,116 @@ use games::*;
fn main() {
App::new()
.add_plugins(BaseGamePlugin {
name: "tetris-rpg".into(),
name: "falling-block-rpg".into(),
target_resolution: (640.0, 480.0).into(),
game_type: GameType::Two,
..default()
})
.add_systems(Startup, init_pieces)
.add_systems(Update, (kb_movement.run_if(on_event::<KeyboardInput>), update_position))
.add_systems(Update, draw_grid)
.add_systems(Update, zoom_camera)
.run();
}
const SCALE: f32 = 30.0;
#[derive(Component, Default, Debug, Clone, Copy)]
struct GridPosition { x: isize, y: isize }
impl From<&GridPosition> for Vec3 {
fn from(GridPosition { x, y }: &GridPosition) -> Vec3 {
Vec3::new((*x as f32) * SCALE, (*y as f32) * SCALE, 0.0)
}
}
impl From<(isize, isize)> for GridPosition {
fn from((x, y): (isize, isize)) -> GridPosition {
GridPosition { x, y }
}
}
impl std::ops::Add for GridPosition {
type Output = Self;
fn add(self, GridPosition { x: x2, y: y2 }: Self) -> Self {
GridPosition { x: self.x + x2, y: self.y + y2 }
}
}
fn init_pieces(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn((
Mesh2d(meshes.add(Rectangle::new(SCALE, SCALE))),
MeshMaterial2d(materials.add(ColorMaterial {
color: WHITE.into(),
..default()
})),
Transform::default(),
GridPosition::default(),
));
}
fn update_position(
mut query: Query<(&GridPosition, &mut Transform), Changed<GridPosition>>,
) {
query.iter_mut().for_each(|(gp, mut t)| {
let tmp: Vec3 = gp.into();
info!("Updating position {:?}", tmp);
t.translation = gp.into();
});
}
fn kb_movement(mut events: EventReader<KeyboardInput>, mut query: Query<&mut GridPosition>) {
events.read().for_each(|KeyboardInput { key_code, state, .. }| {
if let ButtonState::Pressed = state {
let diff: GridPosition = match key_code {
KeyCode::ArrowUp => {
(0, 1)
},
KeyCode::ArrowDown => {
(0, -1)
},
KeyCode::ArrowLeft => {
(-1, 0)
},
KeyCode::ArrowRight => {
(1, 0)
},
_ => (0, 0)
}.into();
query.iter_mut().for_each(|mut gp| {
info!("Moving by {:?}", diff);
*gp = *gp + diff;
});
}
});
}
fn draw_grid(
mut gizmos: Gizmos,
) {
gizmos.grid_2d(
Isometry2d::IDENTITY,
UVec2::new(10, 20),
Vec2::new(SCALE, SCALE),
GREEN
).outer_edges();
}
fn zoom_camera(
mut events: EventReader<MouseWheel>,
mut query: Single<&mut Transform, With<Camera>>,
) {
events.read().for_each(|MouseWheel { unit, y, .. }| {
let movement = match unit {
MouseScrollUnit::Line => y * 1.0,
MouseScrollUnit::Pixel => y * 1.0,
};
query.translation.z += movement;
});
}

@ -120,7 +120,12 @@ fn init_debug_ui(mut commands: Commands) {
flex_direction: FlexDirection::Column,
..default()
},
// When we are showing the debug button, allow this to be visible by default
#[cfg(not(feature = "hide_debug"))]
DebuggingState::Off,
// Hide the "Debug Toggle" button when this feature is enabled
#[cfg(feature = "hide_debug")]
DebuggingState::On,
Name::new("Debug Indicator"),
GlobalZIndex(i32::MAX - 1),
BorderRadius::all(Val::Px(5.0)),

@ -1,3 +1,4 @@
#![feature(stmt_expr_attributes)]
#![allow(ambiguous_glob_reexports)]
#![allow(clippy::type_complexity)]

@ -9,23 +9,27 @@ impl Plugin for LoadingPlugin {
app.init_resource::<TrackLoadingProgress>()
.init_state::<LoadingState>()
.add_systems(PreUpdate, reset_progress)
.add_systems(Startup, spawn_loading_screen)
.add_systems(
Update,
(
track_loading::<AnimationClip>,
track_loading::<AudioSource>,
track_loading::<Font>,
track_loading::<Gltf>,
track_loading::<Image>,
track_loading::<Shader>,
)
.run_if(in_state(LoadingState::Active)),
(
track_loading::<AnimationClip>,
track_loading::<AudioSource>,
track_loading::<Font>,
track_loading::<Gltf>,
track_loading::<Image>,
track_loading::<Shader>,
)
.run_if(in_state(LoadingState::Active)),
toggle_state_visibility::<LoadingState>.run_if(state_changed::<LoadingState>),
),
)
.add_systems(PostUpdate, check_progress);
}
}
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default, Component)]
pub enum LoadingState {
#[default]
Active,
@ -36,6 +40,22 @@ pub enum LoadingState {
#[derive(Resource, Default)]
struct TrackLoadingProgress(Vec<bool>);
fn spawn_loading_screen(mut commands: Commands) {
commands.spawn((
Node {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
},
LoadingState::Active,
children![(
TextColor(WHITE.into()),
Text::new("Credits"),
BackgroundColor(BLACK.into())
)],
));
}
/// At the start of the update clear progress
fn reset_progress(mut progress: ResMut<TrackLoadingProgress>) {
progress.0.clear()

Loading…
Cancel
Save