use new spawn api

This commit is contained in:
2025-04-29 19:55:40 +02:00
parent 11568d57ed
commit 5cc97da98b
8 changed files with 265 additions and 282 deletions

View File

@@ -100,24 +100,22 @@ fn on_trigger_gun(
let mut t = Transform::from_translation(state.pos).with_rotation(rotation); let mut t = Transform::from_translation(state.pos).with_rotation(rotation);
t.translation += t.forward().as_vec3() * 2.0; t.translation += t.forward().as_vec3() * 2.0;
commands commands.spawn((
.spawn(( Name::new("projectile-gun"),
Name::new("projectile-gun"), GunProjectile {
GunProjectile { time: time.elapsed_secs(),
time: time.elapsed_secs(), owner_head: state.head,
owner_head: state.head, },
}, Collider::capsule_endpoints(0.5, Vec3::new(0., 0., 0.), Vec3::new(0., 0., -3.)),
Collider::capsule_endpoints(0.5, Vec3::new(0., 0., 0.), Vec3::new(0., 0., -3.)), CollisionLayers::new(
CollisionLayers::new( LayerMask(GameLayer::Projectile.to_bits()),
LayerMask(GameLayer::Projectile.to_bits()), LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()),
LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()), ),
), Sensor,
Sensor, CollisionEventsEnabled,
CollisionEventsEnabled, Visibility::default(),
Visibility::default(), t,
t, Children::spawn(Spawn(Gizmo {
))
.with_child(Gizmo {
handle: gizmo_assets.add({ handle: gizmo_assets.add({
let mut g = GizmoAsset::default(); let mut g = GizmoAsset::default();
g.line(Vec3::Z * -2., Vec3::Z * 2., LinearRgba::rgb(0.9, 0.9, 0.)); g.line(Vec3::Z * -2., Vec3::Z * 2., LinearRgba::rgb(0.9, 0.9, 0.));
@@ -128,7 +126,8 @@ fn on_trigger_gun(
..default() ..default()
}, },
..default() ..default()
}); })),
));
} }
fn update(mut query: Query<&mut Transform, With<GunProjectile>>) { fn update(mut query: Query<&mut Transform, With<GunProjectile>>) {

View File

@@ -114,39 +114,40 @@ fn on_trigger_missile(
let mesh = assets.projectiles["missile.glb"].clone(); let mesh = assets.projectiles["missile.glb"].clone();
let asset = gltf_assets.get(&mesh).unwrap(); let asset = gltf_assets.get(&mesh).unwrap();
commands commands.spawn((
.spawn(( Name::new("projectile-missle"),
Name::new("projectile-missle"), MissileProjectile {
MissileProjectile { time: time.elapsed_secs(),
time: time.elapsed_secs(), damage: head.damage,
damage: head.damage, },
}, Collider::capsule_endpoints(0.4, Vec3::new(0., 0., 2.), Vec3::new(0., 0., -2.)),
Collider::capsule_endpoints(0.4, Vec3::new(0., 0., 2.), Vec3::new(0., 0., -2.)), CollisionLayers::new(
CollisionLayers::new( LayerMask(GameLayer::Projectile.to_bits()),
LayerMask(GameLayer::Projectile.to_bits()), LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()),
LayerMask(state.target_layer.to_bits() | GameLayer::Level.to_bits()), ),
Sensor,
CollisionEventsEnabled,
Visibility::default(),
t,
children![
(
Transform::from_rotation(Quat::from_rotation_x(PI / 2.).inverse())
.with_scale(Vec3::splat(0.04)),
SceneRoot(asset.scenes[0].clone()),
), ),
Sensor, (
CollisionEventsEnabled, Trail::new(t.translation, LinearRgba::rgb(0.9, 0.9, 0.)),
Visibility::default(), Gizmo {
t, handle: gizmo_assets.add(GizmoAsset::default()),
)) line_config: GizmoLineConfig {
.with_child(( width: 10.,
Transform::from_rotation(Quat::from_rotation_x(PI / 2.).inverse()) ..default()
.with_scale(Vec3::splat(0.04)), },
SceneRoot(asset.scenes[0].clone()),
))
.with_child((
Trail::new(t.translation, LinearRgba::rgb(0.9, 0.9, 0.)),
Gizmo {
handle: gizmo_assets.add(GizmoAsset::default()),
line_config: GizmoLineConfig {
width: 10.,
..default() ..default()
}, },
..default() )
}, ],
)); ));
} }
fn update(mut query: Query<&mut Transform, With<MissileProjectile>>) { fn update(mut query: Query<&mut Transform, With<MissileProjectile>>) {

View File

@@ -29,55 +29,46 @@ pub fn plugin(app: &mut App) {
} }
fn setup(mut commands: Commands, assets: Res<UIAssets>) { fn setup(mut commands: Commands, assets: Res<UIAssets>) {
commands commands.spawn((
.spawn(( Name::new("target-ui"),
Name::new("target-ui"), Node {
Node { position_type: PositionType::Absolute,
position_type: PositionType::Absolute, top: Val::Px(150.0),
top: Val::Px(150.0), left: Val::Px(20.0),
left: Val::Px(20.0), height: Val::Px(74.0),
height: Val::Px(74.0), ..default()
..default() },
}, children![spawn_head_ui(
)) assets.head_bg.clone(),
.with_children(|parent| { assets.head_regular.clone(),
spawn_head_ui( assets.head_damage.clone(),
parent, )],
assets.head_bg.clone(), ));
assets.head_regular.clone(),
assets.head_damage.clone(),
);
});
commands.insert_resource(TargetUi::default()); commands.insert_resource(TargetUi::default());
} }
fn spawn_head_ui( fn spawn_head_ui(bg: Handle<Image>, regular: Handle<Image>, damage: Handle<Image>) -> impl Bundle {
parent: &mut ChildSpawnerCommands,
bg: Handle<Image>,
regular: Handle<Image>,
damage: Handle<Image>,
) {
const SIZE: f32 = 90.0; const SIZE: f32 = 90.0;
const DAMAGE_SIZE: f32 = 74.0; const DAMAGE_SIZE: f32 = 74.0;
parent (
.spawn((Node { Node {
position_type: PositionType::Relative, position_type: PositionType::Relative,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center, align_items: AlignItems::Center,
width: Val::Px(SIZE), width: Val::Px(SIZE),
..default() ..default()
},)) },
.with_children(|parent| { children![
parent.spawn(( (
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(bg), ImageNode::new(bg),
)); ),
parent.spawn(( (
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
@@ -85,38 +76,37 @@ fn spawn_head_ui(
ImageNode::default(), ImageNode::default(),
Visibility::Hidden, Visibility::Hidden,
HeadImage, HeadImage,
)); ),
parent.spawn(( (
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(regular), ImageNode::new(regular),
)); ),
parent (
.spawn((Node { Node {
height: Val::Px(DAMAGE_SIZE), height: Val::Px(DAMAGE_SIZE),
width: Val::Px(DAMAGE_SIZE), width: Val::Px(DAMAGE_SIZE),
..default() ..default()
},)) },
.with_children(|parent| { children![(
parent HeadDamage,
.spawn(( Node {
HeadDamage, position_type: PositionType::Absolute,
Node { display: Display::Block,
position_type: PositionType::Absolute, overflow: Overflow::clip(),
display: Display::Block, top: Val::Px(0.),
overflow: Overflow::clip(), left: Val::Px(0.),
top: Val::Px(0.), right: Val::Px(0.),
left: Val::Px(0.), height: Val::Percent(25.),
right: Val::Px(0.), ..default()
height: Val::Percent(25.), },
..default() children![ImageNode::new(damage)]
}, )]
)) )
.with_child(ImageNode::new(damage)); ],
}); )
});
} }
fn update( fn update(

View File

@@ -2,7 +2,7 @@ use super::{BackbackSwapEvent, Backpack, UiHeadState};
use crate::{ use crate::{
GameState, global_observer, heads::HeadsImages, loading_assets::UIAssets, sounds::PlaySound, GameState, global_observer, heads::HeadsImages, loading_assets::UIAssets, sounds::PlaySound,
}; };
use bevy::prelude::*; use bevy::{ecs::spawn::SpawnIter, prelude::*};
static HEAD_SLOTS: usize = 5; static HEAD_SLOTS: usize = 5;
@@ -57,31 +57,34 @@ pub fn plugin(app: &mut App) {
} }
fn setup(mut commands: Commands, assets: Res<UIAssets>) { fn setup(mut commands: Commands, assets: Res<UIAssets>) {
commands commands.spawn((
.spawn(( Name::new("backpack-ui"),
Name::new("backpack-ui"), BackpackMarker,
BackpackMarker, Visibility::Hidden,
Visibility::Hidden, Node {
Node { position_type: PositionType::Absolute,
position_type: PositionType::Absolute, top: Val::Px(20.0),
top: Val::Px(20.0), right: Val::Px(20.0),
right: Val::Px(20.0), height: Val::Px(74.0),
height: Val::Px(74.0), ..default()
..default() },
}, Children::spawn(SpawnIter((0..HEAD_SLOTS).map({
)) let bg = assets.head_bg.clone();
.with_children(|parent| { let regular = assets.head_regular.clone();
for i in 0..HEAD_SLOTS { let selector = assets.head_selector.clone();
let damage = assets.head_damage.clone();
move |i| {
spawn_head_ui( spawn_head_ui(
parent, bg.clone(),
assets.head_bg.clone(), regular.clone(),
assets.head_regular.clone(), selector.clone(),
assets.head_selector.clone(), damage.clone(),
assets.head_damage.clone(),
i, i,
); )
} }
}); }))),
));
commands.spawn(( commands.spawn((
Name::new("backpack-head-count-ui"), Name::new("backpack-head-count-ui"),
@@ -105,26 +108,25 @@ fn setup(mut commands: Commands, assets: Res<UIAssets>) {
} }
fn spawn_head_ui( fn spawn_head_ui(
parent: &mut ChildSpawnerCommands,
bg: Handle<Image>, bg: Handle<Image>,
regular: Handle<Image>, regular: Handle<Image>,
selector: Handle<Image>, selector: Handle<Image>,
damage: Handle<Image>, damage: Handle<Image>,
head_slot: usize, head_slot: usize,
) { ) -> impl Bundle {
const SIZE: f32 = 90.0; const SIZE: f32 = 90.0;
const DAMAGE_SIZE: f32 = 74.0; const DAMAGE_SIZE: f32 = 74.0;
parent (
.spawn((Node { Node {
position_type: PositionType::Relative, position_type: PositionType::Relative,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center, align_items: AlignItems::Center,
width: Val::Px(SIZE), width: Val::Px(SIZE),
..default() ..default()
},)) },
.with_children(|parent| { children![
parent.spawn(( (
Name::new("selector"), Name::new("selector"),
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
@@ -134,16 +136,16 @@ fn spawn_head_ui(
Visibility::Hidden, Visibility::Hidden,
ImageNode::new(selector).with_flip_y(), ImageNode::new(selector).with_flip_y(),
HeadSelector(head_slot), HeadSelector(head_slot),
)); ),
parent.spawn(( (
Name::new("bg"), Name::new("bg"),
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(bg), ImageNode::new(bg),
)); ),
parent.spawn(( (
Name::new("head"), Name::new("head"),
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
@@ -152,43 +154,40 @@ fn spawn_head_ui(
ImageNode::default(), ImageNode::default(),
Visibility::Hidden, Visibility::Hidden,
HeadImage(head_slot), HeadImage(head_slot),
)); ),
parent.spawn(( (
Name::new("rings"), Name::new("rings"),
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(regular), ImageNode::new(regular),
)); ),
parent (
.spawn(( Name::new("health"),
Name::new("health"), Node {
height: Val::Px(DAMAGE_SIZE),
width: Val::Px(DAMAGE_SIZE),
..default()
},
children![(
Name::new("damage_ring"),
HeadDamage(head_slot),
Node { Node {
height: Val::Px(DAMAGE_SIZE), position_type: PositionType::Absolute,
width: Val::Px(DAMAGE_SIZE), display: Display::Block,
overflow: Overflow::clip(),
top: Val::Px(0.),
left: Val::Px(0.),
right: Val::Px(0.),
height: Val::Percent(0.),
..default() ..default()
}, },
)) children![ImageNode::new(damage)]
.with_children(|parent| { )]
parent )
.spawn(( ],
Name::new("damage_ring"), )
HeadDamage(head_slot),
Node {
position_type: PositionType::Absolute,
display: Display::Block,
overflow: Overflow::clip(),
top: Val::Px(0.),
left: Val::Px(0.),
right: Val::Px(0.),
height: Val::Percent(0.),
..default()
},
))
.with_child(ImageNode::new(damage));
});
});
} }
fn update_visibility( fn update_visibility(

View File

@@ -82,25 +82,24 @@ fn update_ui(
let show_ui = cam_state.look_around || cam_state.cutscene; let show_ui = cam_state.look_around || cam_state.cutscene;
if show_ui { if show_ui {
commands commands.spawn((
.spawn(( CameraUi,
CameraUi, Node {
Node { margin: UiRect::top(Val::Px(20.))
margin: UiRect::top(Val::Px(20.)) .with_left(Val::Auto)
.with_left(Val::Auto) .with_right(Val::Auto),
.with_right(Val::Auto), justify_content: JustifyContent::Center,
justify_content: JustifyContent::Center, ..default()
..default() },
}, children![(
))
.with_child((
Node { Node {
display: Display::Block, display: Display::Block,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(assets.camera.clone()), ImageNode::new(assets.camera.clone()),
)); )],
));
} else { } else {
for entity in query.iter() { for entity in query.iter() {
commands.entity(entity).despawn(); commands.entity(entity).despawn();

View File

@@ -1,5 +1,5 @@
use crate::{GameState, backpack::UiHeadState, loading_assets::UIAssets, player::Player}; use crate::{GameState, backpack::UiHeadState, loading_assets::UIAssets, player::Player};
use bevy::prelude::*; use bevy::{ecs::spawn::SpawnIter, prelude::*};
use bevy_ui_gradients::{AngularColorStop, BackgroundGradient, ConicGradient, Gradient, Position}; use bevy_ui_gradients::{AngularColorStop, BackgroundGradient, ConicGradient, Gradient, Position};
use std::f32::consts::PI; use std::f32::consts::PI;
@@ -36,54 +36,56 @@ pub fn plugin(app: &mut App) {
} }
fn setup(mut commands: Commands, assets: Res<UIAssets>) { fn setup(mut commands: Commands, assets: Res<UIAssets>) {
commands commands.spawn((
.spawn(( Name::new("heads-ui"),
Name::new("heads-ui"), Node {
Node { position_type: PositionType::Absolute,
position_type: PositionType::Absolute, bottom: Val::Px(20.0),
bottom: Val::Px(20.0), right: Val::Px(20.0),
right: Val::Px(20.0), height: Val::Px(74.0),
height: Val::Px(74.0), ..default()
..default() },
}, Children::spawn(SpawnIter((0..HEAD_SLOTS).map({
)) let bg = assets.head_bg.clone();
.with_children(|parent| { let regular = assets.head_regular.clone();
for i in 0..HEAD_SLOTS { let selector = assets.head_selector.clone();
let damage = assets.head_damage.clone();
move |i| {
spawn_head_ui( spawn_head_ui(
parent, bg.clone(),
assets.head_bg.clone(), regular.clone(),
assets.head_regular.clone(), selector.clone(),
assets.head_selector.clone(), damage.clone(),
assets.head_damage.clone(),
i, i,
); )
} }
}); }))),
));
commands.init_resource::<UiActiveHeads>(); commands.init_resource::<UiActiveHeads>();
} }
fn spawn_head_ui( fn spawn_head_ui(
parent: &mut ChildSpawnerCommands,
bg: Handle<Image>, bg: Handle<Image>,
regular: Handle<Image>, regular: Handle<Image>,
selector: Handle<Image>, selector: Handle<Image>,
damage: Handle<Image>, damage: Handle<Image>,
head_slot: usize, head_slot: usize,
) { ) -> impl Bundle {
const SIZE: f32 = 90.0; const SIZE: f32 = 90.0;
const DAMAGE_SIZE: f32 = 74.0; const DAMAGE_SIZE: f32 = 74.0;
parent (
.spawn((Node { Node {
position_type: PositionType::Relative, position_type: PositionType::Relative,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center, align_items: AlignItems::Center,
width: Val::Px(SIZE), width: Val::Px(SIZE),
..default() ..default()
},)) },
.with_children(|parent| { children![
parent.spawn(( (
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(-30.0), top: Val::Px(-30.0),
@@ -92,16 +94,15 @@ fn spawn_head_ui(
Visibility::Hidden, Visibility::Hidden,
ImageNode::new(selector), ImageNode::new(selector),
HeadSelector(head_slot), HeadSelector(head_slot),
)); ),
(
parent.spawn((
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(bg), ImageNode::new(bg),
)); ),
parent.spawn(( (
Name::new("head-icon"), Name::new("head-icon"),
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
@@ -120,38 +121,37 @@ fn spawn_head_ui(
ImageNode::default(), ImageNode::default(),
Visibility::Hidden, Visibility::Hidden,
HeadImage(head_slot), HeadImage(head_slot),
)); ),
parent.spawn(( (
Node { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
ImageNode::new(regular), ImageNode::new(regular),
)); ),
parent (
.spawn((Node { Node {
height: Val::Px(DAMAGE_SIZE), height: Val::Px(DAMAGE_SIZE),
width: Val::Px(DAMAGE_SIZE), width: Val::Px(DAMAGE_SIZE),
..default() ..default()
},)) },
.with_children(|parent| { children![(
parent HeadDamage(head_slot),
.spawn(( Node {
HeadDamage(head_slot), position_type: PositionType::Absolute,
Node { display: Display::Block,
position_type: PositionType::Absolute, overflow: Overflow::clip(),
display: Display::Block, top: Val::Px(0.),
overflow: Overflow::clip(), left: Val::Px(0.),
top: Val::Px(0.), right: Val::Px(0.),
left: Val::Px(0.), height: Val::Percent(25.),
right: Val::Px(0.), ..default()
height: Val::Percent(25.), },
..default() children![ImageNode::new(damage)]
}, )]
)) )
.with_child(ImageNode::new(damage)); ],
}); )
});
} }
fn update( fn update(

View File

@@ -28,24 +28,23 @@ fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<
let angle = rand::random::<f32>() * PI * 2.; let angle = rand::random::<f32>() * PI * 2.;
let spawn_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize(); let spawn_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize();
commands commands.spawn((
.spawn(( Name::new("key"),
Name::new("key"), Key(id.clone()),
Key(id.clone()), Transform::from_translation(*position),
Transform::from_translation(*position), Visibility::default(),
Visibility::default(), Collider::sphere(1.5),
Collider::sphere(1.5), ExternalImpulse::new(spawn_dir * 180.).with_persistence(false),
ExternalImpulse::new(spawn_dir * 180.).with_persistence(false), LockedAxes::ROTATION_LOCKED,
LockedAxes::ROTATION_LOCKED, RigidBody::Dynamic,
RigidBody::Dynamic, CollisionEventsEnabled,
CollisionEventsEnabled, Restitution::new(0.6),
Restitution::new(0.6), Children::spawn(Spawn((
))
.with_child((
Billboard, Billboard,
SquishAnimation(2.6), SquishAnimation(2.6),
SceneRoot(assets.mesh_key.clone()), SceneRoot(assets.mesh_key.clone()),
)); ))),
));
} }
fn collect_key( fn collect_key(

View File

@@ -64,37 +64,33 @@ fn spawn(
let gravity = Vector::NEG_Y * 40.0; let gravity = Vector::NEG_Y * 40.0;
let collider = Collider::capsule(0.9, 1.2); let collider = Collider::capsule(0.9, 1.2);
commands commands.spawn((
.spawn(( Name::from("player"),
Name::from("player"), Player,
Player, ActiveHead(0),
ActiveHead(0), ActiveHeads::new([
ActiveHeads::new([ Some(HeadState::new(0, heads_db.as_ref())),
Some(HeadState::new(0, heads_db.as_ref())), Some(HeadState::new(3, heads_db.as_ref())),
Some(HeadState::new(3, heads_db.as_ref())), Some(HeadState::new(6, heads_db.as_ref())),
Some(HeadState::new(6, heads_db.as_ref())), Some(HeadState::new(10, heads_db.as_ref())),
Some(HeadState::new(10, heads_db.as_ref())), Some(HeadState::new(9, heads_db.as_ref())),
Some(HeadState::new(9, heads_db.as_ref())), ]),
]), Hitpoints::new(100),
Hitpoints::new(100), CameraTarget,
CameraTarget, transform,
transform, Visibility::default(),
// LockedAxes::ROTATION_LOCKED, todo
CollisionLayers::new(LayerMask(GameLayer::Player.to_bits()), LayerMask::ALL),
CharacterControllerBundle::new(collider, gravity),
children![(
Name::new("player-rig"),
Transform::default(),
Visibility::default(), Visibility::default(),
// LockedAxes::ROTATION_LOCKED, todo PlayerBodyMesh,
CollisionLayers::new(LayerMask(GameLayer::Player.to_bits()), LayerMask::ALL), CameraArmRotation,
CharacterControllerBundle::new(collider, gravity), children![AnimatedCharacter(0)]
)) )],
.with_children(|parent| { ));
parent
.spawn((
Name::new("player-rig"),
Transform::default(),
Visibility::default(),
PlayerBodyMesh,
CameraArmRotation,
))
.with_child(AnimatedCharacter(0));
});
commands.spawn(( commands.spawn((
AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")), AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")),