ammo system

* heads have abilities
* health and ammo shows in ui
This commit is contained in:
2025-04-02 01:35:02 +08:00
parent 8187eb58a9
commit 01e6e944d3
13 changed files with 360 additions and 234 deletions

View File

@@ -1,4 +1,4 @@
use super::{Projectile, TriggerState}; use super::{Projectile, TriggerGun};
use crate::{ use crate::{
GameState, GameState,
aim::AimState, aim::AimState,
@@ -50,46 +50,30 @@ fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Spr
} }
fn on_trigger_state( fn on_trigger_state(
trigger: Trigger<TriggerState>, trigger: Trigger<TriggerGun>,
mut commands: Commands, mut commands: Commands,
aim: Res<AimState>, aim: Res<AimState>,
player_rot: Query<&Transform, With<PlayerRig>>,
player: Query<(&Transform, &Player)>,
target_transform: Query<&Transform, (Without<Player>, Without<PlayerRig>)>, target_transform: Query<&Transform, (Without<Player>, Without<PlayerRig>)>,
time: Res<Time>, time: Res<Time>,
mut polyline_materials: ResMut<Assets<PolylineMaterial>>, mut polyline_materials: ResMut<Assets<PolylineMaterial>>,
mut polylines: ResMut<Assets<Polyline>>, mut polylines: ResMut<Assets<Polyline>>,
) { ) {
if matches!(trigger.event(), TriggerState::Active) { let state = trigger.0;
let Some((player_pos, player_head)) =
player.iter().next().map(|(t, p)| (t.translation, p.0))
else {
return;
};
// TODO: proper weapon classes
if ![2, 3, 9].contains(&player_head) {
return;
}
commands.trigger(PlaySound::Gun); commands.trigger(PlaySound::Gun);
let Some(rotation) = player_rot.iter().next().map(|t| t.rotation) else {
return;
};
let rotation = if let Some(target) = aim.target { let rotation = if let Some(target) = aim.target {
let t = target_transform let t = target_transform
.get(target) .get(target)
.expect("target must have transform"); .expect("target must have transform");
Transform::from_translation(player_pos) Transform::from_translation(state.pos)
.looking_at(t.translation, Vec3::Y) .looking_at(t.translation, Vec3::Y)
.rotation .rotation
} else { } else {
rotation.mul_quat(Quat::from_rotation_y(PI)) state.rot.mul_quat(Quat::from_rotation_y(PI))
}; };
let mut t = Transform::from_translation(player_pos).with_rotation(rotation); let mut t = Transform::from_translation(state.pos).with_rotation(rotation);
t.translation += t.forward().as_vec3() * 2.; t.translation += t.forward().as_vec3() * 2.;
commands commands
@@ -120,7 +104,6 @@ fn on_trigger_state(
})), })),
..default() ..default()
}); });
}
} }
fn update(mut query: Query<&mut Transform, With<GunProjectile>>) { fn update(mut query: Query<&mut Transform, With<GunProjectile>>) {

View File

@@ -1,7 +1,13 @@
mod gun; mod gun;
mod thrown; mod thrown;
use crate::{GameState, npc::Hit, tb_entities::EnemySpawn}; use crate::{
GameState,
active_heads::ActiveHeads,
npc::Hit,
player::{Player, PlayerRig},
tb_entities::EnemySpawn,
};
use avian3d::prelude::*; use avian3d::prelude::*;
use bevy::prelude::*; use bevy::prelude::*;
@@ -16,11 +22,33 @@ pub enum TriggerState {
Inactive, Inactive,
} }
#[derive(Debug, Copy, Clone, PartialEq, Reflect)]
pub enum HeadAbility {
None,
Arrow,
Thrown,
Gun,
}
#[derive(Debug, Reflect, Clone, Copy)]
pub struct PlayerTriggerState {
dir: Dir3,
rot: Quat,
pos: Vec3,
}
#[derive(Event, Reflect)]
pub struct TriggerGun(pub PlayerTriggerState);
#[derive(Event, Reflect)]
pub struct TriggerThrow(pub PlayerTriggerState);
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_plugins(gun::plugin); app.add_plugins(gun::plugin);
app.add_plugins(thrown::plugin); app.add_plugins(thrown::plugin);
app.add_systems(Update, enemy_hit.run_if(in_state(GameState::Playing))); app.add_systems(Update, enemy_hit.run_if(in_state(GameState::Playing)));
app.add_observer(on_trigger_state);
} }
fn enemy_hit( fn enemy_hit(
@@ -47,3 +75,44 @@ fn enemy_hit(
commands.entity(enemy_entity).trigger(Hit { damage }); commands.entity(enemy_entity).trigger(Hit { damage });
} }
} }
fn on_trigger_state(
trigger: Trigger<TriggerState>,
mut commands: Commands,
player_rot: Query<&Transform, With<PlayerRig>>,
player_transform: Query<&Transform, With<Player>>,
mut active_heads: ResMut<ActiveHeads>,
) {
if matches!(trigger.event(), TriggerState::Active) {
let Some(state) = active_heads.current() else {
return;
};
if !state.has_ammo() {
//TOOD: play sound
return;
}
let Some(transform) = player_transform.iter().next().copied() else {
return;
};
let Some((rot, dir)) = player_rot.iter().next().map(|t| (t.rotation, t.forward())) else {
return;
};
let trigger_state = PlayerTriggerState {
dir,
rot,
pos: transform.translation,
};
active_heads.use_ammo();
match state.ability {
HeadAbility::Thrown => commands.trigger(TriggerThrow(trigger_state)),
HeadAbility::Gun => commands.trigger(TriggerGun(trigger_state)),
_ => (),
};
}
}

View File

@@ -1,4 +1,4 @@
use super::TriggerState; use super::TriggerThrow;
use crate::{ use crate::{
GameState, GameState,
aim::AimState, aim::AimState,
@@ -83,34 +83,16 @@ fn setup(mut commands: Commands, assets: Res<GameAssets>, mut sprite_params: Spr
} }
fn on_trigger_state( fn on_trigger_state(
trigger: Trigger<TriggerState>, trigger: Trigger<TriggerThrow>,
mut commands: Commands, mut commands: Commands,
aim: Res<AimState>, aim: Res<AimState>,
player_rot: Query<&Transform, With<PlayerRig>>,
player: Query<(&Transform, &Player)>,
target_transform: Query<&Transform, (Without<Player>, Without<PlayerRig>)>, target_transform: Query<&Transform, (Without<Player>, Without<PlayerRig>)>,
assets: Res<GameAssets>, assets: Res<GameAssets>,
) { ) {
if matches!(trigger.event(), TriggerState::Active) { let state = trigger.event().0;
let Some((player_pos, player_head)) =
player.iter().next().map(|(t, p)| (t.translation, p.0))
else {
return;
};
// TODO: proper weapon classes
if ![0, 8, 16, 17].contains(&player_head) {
return;
}
commands.trigger(PlaySound::Throw); commands.trigger(PlaySound::Throw);
let Some((rotation, player_forward)) =
player_rot.iter().next().map(|t| (t.rotation, t.forward()))
else {
return;
};
const SPEED: f32 = 35.; const SPEED: f32 = 35.;
let vel = if let Some(target) = aim.target { let vel = if let Some(target) = aim.target {
@@ -119,7 +101,7 @@ fn on_trigger_state(
.expect("target must have transform"); .expect("target must have transform");
launch_velocity( launch_velocity(
player_pos + player_forward.as_vec3() * 2., state.pos + state.dir.as_vec3() * 2.,
t.translation, t.translation,
SPEED, SPEED,
9.81, 9.81,
@@ -127,11 +109,11 @@ fn on_trigger_state(
.map(|(low, _)| low) .map(|(low, _)| low)
.unwrap() .unwrap()
} else { } else {
rotation.mul_quat(Quat::from_rotation_y(-PI / 2.)) state.rot.mul_quat(Quat::from_rotation_y(-PI / 2.))
* (Vec3::new(2., 1., 0.).normalize() * SPEED) * (Vec3::new(2., 1., 0.).normalize() * SPEED)
}; };
let t = Transform::from_translation(player_pos); let t = Transform::from_translation(state.pos);
commands commands
.spawn(( .spawn((
@@ -153,7 +135,6 @@ fn on_trigger_state(
Transform::from_scale(Vec3::splat(10.)), Transform::from_scale(Vec3::splat(10.)),
SceneRoot(assets.molotov.clone()), SceneRoot(assets.molotov.clone()),
)); ));
}
} }
fn shot_collision( fn shot_collision(

138
src/active_heads.rs Normal file
View File

@@ -0,0 +1,138 @@
use crate::{
abilities::HeadAbility,
backpack::{BackbackSwapEvent, Backpack},
sounds::PlaySound,
};
use bevy::prelude::*;
pub static HEAD_COUNT: usize = 18;
pub static HEAD_SLOTS: usize = 5;
#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
pub struct HeadState {
pub head: usize,
pub ability: HeadAbility,
pub health: u32,
pub health_max: u32,
pub ammo: u32,
pub ammo_max: u32,
}
impl HeadState {
pub fn new(head: usize, ammo: u32) -> Self {
Self {
head,
health: 100,
health_max: 100,
ammo,
ammo_max: ammo,
ability: HeadAbility::None,
}
}
fn with_ability(mut self, ability: HeadAbility) -> Self {
self.ability = ability;
self
}
pub fn has_ammo(&self) -> bool {
self.ammo > 0
}
}
#[derive(Resource, Default, Reflect)]
#[reflect(Resource)]
pub struct ActiveHeads {
heads: [Option<HeadState>; 5],
current_slot: usize,
}
impl ActiveHeads {
pub fn current(&self) -> Option<HeadState> {
self.heads[self.current_slot]
}
pub fn use_ammo(&mut self) {
let Some(head) = &mut self.heads[self.current_slot] else {
error!("cannot use ammo of empty head");
return;
};
head.ammo = head.ammo.saturating_sub(1);
}
pub fn slot(&self) -> usize {
self.current_slot
}
pub fn head(&self, slot: usize) -> Option<HeadState> {
self.heads[slot]
}
}
#[derive(Event, Reflect)]
pub enum SelectActiveHead {
Left,
Right,
}
#[derive(Event)]
pub struct HeadChanged(pub usize);
pub fn plugin(app: &mut App) {
app.insert_resource(ActiveHeads {
heads: [
Some(HeadState::new(0, 10).with_ability(HeadAbility::Thrown)),
Some(HeadState::new(3, 10).with_ability(HeadAbility::Gun)),
Some(HeadState::new(6, 10).with_ability(HeadAbility::Arrow)),
Some(HeadState::new(8, 10).with_ability(HeadAbility::Thrown)),
Some(HeadState::new(9, 10).with_ability(HeadAbility::Gun)),
],
current_slot: 0,
});
app.add_observer(on_select_active_head);
app.add_observer(on_swap_backpack);
}
fn on_select_active_head(
trigger: Trigger<SelectActiveHead>,
mut commands: Commands,
mut res: ResMut<ActiveHeads>,
) {
match trigger.event() {
SelectActiveHead::Right => {
res.current_slot = (res.current_slot + 1) % HEAD_SLOTS;
}
SelectActiveHead::Left => {
res.current_slot = (res.current_slot + (HEAD_SLOTS - 1)) % HEAD_SLOTS;
}
}
commands.trigger(PlaySound::Selection);
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
}
fn on_swap_backpack(
trigger: Trigger<BackbackSwapEvent>,
mut commands: Commands,
mut res: ResMut<ActiveHeads>,
mut backpack: ResMut<Backpack>,
) {
let backpack_slot = trigger.event().0;
let head = backpack.heads.get(backpack_slot).unwrap();
let current_active_slot = res.current_slot;
let current_active_head = res.heads[current_active_slot];
res.heads[current_active_slot] = Some(*head);
if let Some(old_active) = current_active_head {
backpack.heads[backpack_slot] = old_active;
} else {
backpack.heads.remove(backpack_slot);
}
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
}

View File

@@ -1,7 +1,7 @@
use super::AimState; use super::AimState;
use crate::{ use crate::{
GameState, GameState,
backpack::BackpackHead, backpack::UiHeadState,
heads_ui::HeadsImages, heads_ui::HeadsImages,
loading_assets::UIAssets, loading_assets::UIAssets,
npc::{Hitpoints, NpcHead}, npc::{Hitpoints, NpcHead},
@@ -18,7 +18,7 @@ struct HeadDamage;
#[derive(Resource, Default, PartialEq)] #[derive(Resource, Default, PartialEq)]
struct TargetUi { struct TargetUi {
head: Option<BackpackHead>, head: Option<UiHeadState>,
} }
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
@@ -150,7 +150,7 @@ fn sync(
let mut new_state = None; let mut new_state = None;
if let Some(e) = aim.target { if let Some(e) = aim.target {
if let Ok((hp, head)) = target_data.get(e) { if let Ok((hp, head)) = target_data.get(e) {
new_state = Some(BackpackHead { new_state = Some(UiHeadState {
head: head.0, head: head.0,
health: hp.health(), health: hp.health(),
ammo: 1., ammo: 1.,

View File

@@ -1,4 +1,4 @@
use super::{BackbackSwapEvent, Backpack, BackpackHead}; use super::{BackbackSwapEvent, Backpack, UiHeadState};
use crate::{GameState, heads_ui::HeadsImages, loading_assets::UIAssets, sounds::PlaySound}; use crate::{GameState, heads_ui::HeadsImages, loading_assets::UIAssets, sounds::PlaySound};
use bevy::prelude::*; use bevy::prelude::*;
@@ -29,7 +29,7 @@ struct HeadDamage(pub usize);
#[derive(Resource, Default, Debug)] #[derive(Resource, Default, Debug)]
struct BackpackUiState { struct BackpackUiState {
heads: [Option<BackpackHead>; 5], heads: [Option<UiHeadState>; 5],
scroll: usize, scroll: usize,
count: usize, count: usize,
current_slot: usize, current_slot: usize,
@@ -316,7 +316,7 @@ fn sync(backpack: &Res<Backpack>, state: &mut ResMut<BackpackUiState>) {
for i in 0..HEAD_SLOTS { for i in 0..HEAD_SLOTS {
if let Some(head) = backpack.heads.get(i + state.scroll) { if let Some(head) = backpack.heads.get(i + state.scroll) {
state.heads[i] = Some(*head); state.heads[i] = Some(UiHeadState::from(*head));
} else { } else {
state.heads[i] = None; state.heads[i] = None;
} }

View File

@@ -1,38 +1,18 @@
mod backpack_ui; mod backpack_ui;
mod ui_head_state;
use crate::{GameState, heads_ui::HEAD_COUNT}; use crate::{
GameState,
active_heads::{HEAD_COUNT, HeadState},
};
use bevy::prelude::*; use bevy::prelude::*;
pub use backpack_ui::BackpackAction; pub use backpack_ui::BackpackAction;
pub use ui_head_state::UiHeadState;
#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
pub struct BackpackHead {
pub head: usize,
pub health: f32,
pub ammo: f32,
}
impl BackpackHead {
pub fn new(head: usize) -> Self {
Self {
head,
health: 1.0,
ammo: 1.0,
}
}
pub fn damage(&self) -> f32 {
1. - self.health
}
pub fn ammo_used(&self) -> f32 {
1. - self.ammo
}
}
#[derive(Resource, Default)] #[derive(Resource, Default)]
pub struct Backpack { pub struct Backpack {
pub heads: Vec<BackpackHead>, pub heads: Vec<HeadState>,
} }
#[derive(Event)] #[derive(Event)]
@@ -47,11 +27,7 @@ pub fn plugin(app: &mut App) {
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
commands.insert_resource(Backpack { commands.insert_resource(Backpack {
heads: (0usize..HEAD_COUNT) heads: (0usize..HEAD_COUNT)
.map(|i| BackpackHead { .map(|i| HeadState::new(i, 10))
head: i,
health: 1.,
ammo: 1.,
})
.collect(), .collect(),
}); });
} }

View File

@@ -0,0 +1,30 @@
use bevy::prelude::*;
use crate::active_heads::HeadState;
#[derive(Clone, Copy, Debug, PartialEq, Reflect, Default)]
pub struct UiHeadState {
pub head: usize,
pub health: f32,
pub ammo: f32,
}
impl UiHeadState {
pub fn damage(&self) -> f32 {
1. - self.health
}
pub fn ammo_used(&self) -> f32 {
1. - self.ammo
}
}
impl From<HeadState> for UiHeadState {
fn from(value: HeadState) -> Self {
Self {
head: value.head,
ammo: value.ammo as f32 / value.ammo_max as f32,
health: value.health as f32 / value.health_max as f32,
}
}
}

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
GameState, abilities::TriggerState, backpack::BackpackAction, heads_ui::SelectActiveHead, GameState, abilities::TriggerState, active_heads::SelectActiveHead, backpack::BackpackAction,
}; };
use bevy::{ use bevy::{
input::{ input::{

View File

@@ -1,23 +1,14 @@
use crate::{ use crate::{
GameState, GameState,
backpack::{BackbackSwapEvent, Backpack, BackpackHead}, active_heads::{ActiveHeads, HEAD_COUNT, HEAD_SLOTS},
backpack::UiHeadState,
loading_assets::UIAssets, loading_assets::UIAssets,
player::head_id_to_str, player::head_id_to_str,
sounds::PlaySound,
}; };
use bevy::prelude::*; use bevy::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;
pub static HEAD_COUNT: usize = 18;
static HEAD_SLOTS: usize = 5;
#[derive(Event, Reflect)]
pub enum SelectActiveHead {
Left,
Right,
}
#[derive(Component, Reflect, Default)] #[derive(Component, Reflect, Default)]
#[reflect(Component)] #[reflect(Component)]
struct HeadSelector(pub usize); struct HeadSelector(pub usize);
@@ -37,25 +28,20 @@ pub struct HeadsImages {
#[derive(Resource, Default, Reflect)] #[derive(Resource, Default, Reflect)]
#[reflect(Resource)] #[reflect(Resource)]
pub struct ActiveHeads { struct UiActiveHeads {
heads: [Option<BackpackHead>; 5], heads: [Option<UiHeadState>; 5],
current_slot: usize, current_slot: usize,
} }
#[derive(Event)]
pub struct HeadChanged(pub usize);
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.register_type::<HeadDamage>(); app.register_type::<HeadDamage>();
app.register_type::<ActiveHeads>(); app.register_type::<UiActiveHeads>();
app.add_systems(OnEnter(GameState::Playing), setup); app.add_systems(OnEnter(GameState::Playing), setup);
app.add_systems( app.add_systems(
Update, Update,
(update, update_ammo, update_health).run_if(in_state(GameState::Playing)), (sync, update, update_ammo, update_health).run_if(in_state(GameState::Playing)),
); );
app.add_observer(on_select_active_head);
app.add_observer(on_swap_backpack);
} }
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<UIAssets>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<UIAssets>) {
@@ -87,16 +73,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<UIA
commands.insert_resource(HeadsImages { heads }); commands.insert_resource(HeadsImages { heads });
commands.insert_resource(ActiveHeads { commands.init_resource::<UiActiveHeads>();
heads: [
Some(BackpackHead::new(0)),
Some(BackpackHead::new(3)),
Some(BackpackHead::new(6)),
Some(BackpackHead::new(8)),
Some(BackpackHead::new(9)),
],
current_slot: 0,
});
} }
fn spawn_head_ui( fn spawn_head_ui(
@@ -190,7 +167,7 @@ fn spawn_head_ui(
} }
fn update( fn update(
res: Res<ActiveHeads>, res: Res<UiActiveHeads>,
heads_images: Res<HeadsImages>, heads_images: Res<HeadsImages>,
mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>, mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>,
mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>, mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>,
@@ -214,7 +191,10 @@ fn update(
} }
} }
fn update_ammo(res: Res<ActiveHeads>, mut gradients: Query<(&mut BackgroundGradient, &HeadImage)>) { fn update_ammo(
res: Res<UiActiveHeads>,
mut gradients: Query<(&mut BackgroundGradient, &HeadImage)>,
) {
if res.is_changed() { if res.is_changed() {
for (mut gradient, HeadImage(head)) in gradients.iter_mut() { for (mut gradient, HeadImage(head)) in gradients.iter_mut() {
if let Some(head) = res.heads[*head] { if let Some(head) = res.heads[*head] {
@@ -230,7 +210,7 @@ fn update_ammo(res: Res<ActiveHeads>, mut gradients: Query<(&mut BackgroundGradi
} }
} }
fn update_health(res: Res<ActiveHeads>, mut query: Query<(&mut Node, &HeadDamage)>) { fn update_health(res: Res<UiActiveHeads>, mut query: Query<(&mut Node, &HeadDamage)>) {
if res.is_changed() { if res.is_changed() {
for (mut node, HeadDamage(head)) in query.iter_mut() { for (mut node, HeadDamage(head)) in query.iter_mut() {
node.height = node.height =
@@ -239,44 +219,11 @@ fn update_health(res: Res<ActiveHeads>, mut query: Query<(&mut Node, &HeadDamage
} }
} }
fn on_select_active_head( fn sync(active: Res<ActiveHeads>, mut state: ResMut<UiActiveHeads>) {
trigger: Trigger<SelectActiveHead>, if active.is_changed() {
mut commands: Commands, state.current_slot = active.slot();
mut res: ResMut<ActiveHeads>, for i in 0..HEAD_SLOTS {
) { state.heads[i] = active.head(i).map(UiHeadState::from);
match trigger.event() {
SelectActiveHead::Right => {
res.current_slot = (res.current_slot + 1) % HEAD_SLOTS;
}
SelectActiveHead::Left => {
res.current_slot = (res.current_slot + (HEAD_SLOTS - 1)) % HEAD_SLOTS;
} }
} }
commands.trigger(PlaySound::Selection);
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
}
fn on_swap_backpack(
trigger: Trigger<BackbackSwapEvent>,
mut commands: Commands,
mut res: ResMut<ActiveHeads>,
mut backpack: ResMut<Backpack>,
) {
let backpack_slot = trigger.event().0;
let head = backpack.heads.get(backpack_slot).unwrap();
let current_active_slot = res.current_slot;
let current_active_head = res.heads[current_active_slot];
res.heads[current_active_slot] = Some(*head);
if let Some(old_active) = current_active_head {
backpack.heads[backpack_slot] = old_active;
} else {
backpack.heads.remove(backpack_slot);
}
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
} }

View File

@@ -1,4 +1,5 @@
mod abilities; mod abilities;
mod active_heads;
mod aim; mod aim;
mod alien; mod alien;
mod backpack; mod backpack;
@@ -116,6 +117,7 @@ fn main() {
app.add_plugins(loading_map::plugin); app.add_plugins(loading_map::plugin);
app.add_plugins(sprite_3d_animation::plugin); app.add_plugins(sprite_3d_animation::plugin);
app.add_plugins(abilities::plugin); app.add_plugins(abilities::plugin);
app.add_plugins(active_heads::plugin);
app.init_state::<GameState>(); app.init_state::<GameState>();

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
GameState, heads_ui::HEAD_COUNT, keys::KeySpawn, player::head_id_to_str, sounds::PlaySound, GameState, active_heads::HEAD_COUNT, keys::KeySpawn, player::head_id_to_str, sounds::PlaySound,
tb_entities::EnemySpawn, tb_entities::EnemySpawn,
}; };
use bevy::prelude::*; use bevy::prelude::*;

View File

@@ -1,5 +1,6 @@
use crate::{ use crate::{
GameState, GameState,
active_heads::HeadChanged,
alien::Animations, alien::Animations,
camera::{CameraArmRotation, CameraTarget}, camera::{CameraArmRotation, CameraTarget},
cash::{Cash, CashCollectEvent}, cash::{Cash, CashCollectEvent},
@@ -7,7 +8,6 @@ use crate::{
Controls, Controls,
controller::{CharacterControllerBundle, MovementBundle, PlayerMovement}, controller::{CharacterControllerBundle, MovementBundle, PlayerMovement},
}, },
heads_ui::HeadChanged,
loading_assets::GameAssets, loading_assets::GameAssets,
physics_layers::GameLayer, physics_layers::GameLayer,
sounds::PlaySound, sounds::PlaySound,