151 lines
4.4 KiB
Rust
151 lines
4.4 KiB
Rust
use crate::{
|
|
GameState,
|
|
cash::{Cash, CashCollectEvent},
|
|
character::{AnimatedCharacter, Character},
|
|
global_observer,
|
|
head::ActiveHead,
|
|
heads::HeadChanged,
|
|
heads_database::{HeadControls, HeadsDatabase},
|
|
loading_assets::AudioAssets,
|
|
sounds::PlaySound,
|
|
};
|
|
use avian3d::prelude::*;
|
|
use bevy::{
|
|
input::common_conditions::input_just_pressed,
|
|
prelude::*,
|
|
window::{CursorGrabMode, PrimaryWindow},
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
|
#[require(Character)]
|
|
pub struct Player;
|
|
|
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
|
#[require(Transform, Visibility)]
|
|
pub struct PlayerBodyMesh;
|
|
|
|
pub fn plugin(app: &mut App) {
|
|
app.add_systems(Startup, (toggle_cursor_system, cursor_recenter));
|
|
app.add_systems(
|
|
Update,
|
|
(
|
|
collect_cash,
|
|
setup_animations_marker_for_player,
|
|
toggle_cursor_system.run_if(input_just_pressed(KeyCode::Escape)),
|
|
)
|
|
.run_if(in_state(GameState::Playing)),
|
|
);
|
|
|
|
global_observer!(app, on_update_head_mesh);
|
|
}
|
|
|
|
fn cursor_recenter(q_windows: Single<&mut Window, With<PrimaryWindow>>) {
|
|
let mut primary_window = q_windows;
|
|
let center = Vec2::new(
|
|
primary_window.resolution.width() / 2.,
|
|
primary_window.resolution.height() / 2.,
|
|
);
|
|
primary_window.set_cursor_position(Some(center));
|
|
}
|
|
|
|
fn toggle_grab_cursor(window: &mut Window) {
|
|
match window.cursor_options.grab_mode {
|
|
CursorGrabMode::None => {
|
|
window.cursor_options.grab_mode = CursorGrabMode::Confined;
|
|
window.cursor_options.visible = false;
|
|
}
|
|
_ => {
|
|
window.cursor_options.grab_mode = CursorGrabMode::None;
|
|
window.cursor_options.visible = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn toggle_cursor_system(mut window: Single<&mut Window, With<PrimaryWindow>>) {
|
|
toggle_grab_cursor(&mut window);
|
|
}
|
|
|
|
fn collect_cash(
|
|
mut commands: Commands,
|
|
mut collision_event_reader: EventReader<CollisionStarted>,
|
|
query_player: Query<&Player>,
|
|
query_cash: Query<&Cash>,
|
|
) {
|
|
for CollisionStarted(e1, e2) in collision_event_reader.read() {
|
|
let collect = if query_player.contains(*e1) && query_cash.contains(*e2) {
|
|
Some(*e2)
|
|
} else if query_player.contains(*e2) && query_cash.contains(*e1) {
|
|
Some(*e1)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(cash) = collect {
|
|
commands.trigger(CashCollectEvent);
|
|
commands.entity(cash).despawn();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn setup_animations_marker_for_player(
|
|
mut commands: Commands,
|
|
animation_handles: Query<Entity, Added<AnimationGraphHandle>>,
|
|
child_of: Query<&ChildOf>,
|
|
player_rig: Query<&ChildOf, With<PlayerBodyMesh>>,
|
|
) {
|
|
for animation_rig in animation_handles.iter() {
|
|
for ancestor in child_of.iter_ancestors(animation_rig) {
|
|
if let Ok(rig_child_of) = player_rig.get(ancestor) {
|
|
commands.entity(rig_child_of.parent());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn on_update_head_mesh(
|
|
trigger: Trigger<HeadChanged>,
|
|
mut commands: Commands,
|
|
body_mesh: Single<(Entity, &Children), With<PlayerBodyMesh>>,
|
|
animated_characters: Query<&AnimatedCharacter>,
|
|
mut player: Single<&mut ActiveHead, With<Player>>,
|
|
head_db: Res<HeadsDatabase>,
|
|
audio_assets: Res<AudioAssets>,
|
|
sfx: Query<&AudioPlayer>,
|
|
) -> Result {
|
|
let (body_mesh, mesh_children) = *body_mesh;
|
|
|
|
let animated_char = mesh_children
|
|
.iter()
|
|
.find(|child| animated_characters.contains(*child))
|
|
.ok_or("tried to update head mesh before AnimatedCharacter was readded")?;
|
|
|
|
player.0 = trigger.0;
|
|
|
|
let head_str = head_db.head_key(trigger.0);
|
|
|
|
commands.trigger(PlaySound::Head(head_str.to_string()));
|
|
|
|
commands
|
|
.entity(animated_char)
|
|
.insert(AnimatedCharacter::new(trigger.0));
|
|
|
|
//TODO: make part of full character mesh later
|
|
for child in mesh_children.iter().filter(|child| sfx.contains(*child)) {
|
|
commands.entity(child).despawn();
|
|
}
|
|
if head_db.head_stats(trigger.0).controls == HeadControls::Plane {
|
|
commands.entity(body_mesh).with_child((
|
|
Name::new("sfx"),
|
|
AudioPlayer::new(audio_assets.jet.clone()),
|
|
PlaybackSettings {
|
|
mode: bevy::audio::PlaybackMode::Loop,
|
|
..Default::default()
|
|
},
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|