use gamestates and assetloader
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
mod target_ui;
|
||||
|
||||
use crate::{
|
||||
GameState,
|
||||
billboards::Billboard,
|
||||
loading_assets::UIAssets,
|
||||
player::{Player, PlayerRig},
|
||||
tb_entities::EnemySpawn,
|
||||
};
|
||||
@@ -43,14 +45,17 @@ pub fn plugin(app: &mut App) {
|
||||
|
||||
app.add_plugins(target_ui::plugin);
|
||||
|
||||
app.add_systems(Update, (update, move_marker));
|
||||
app.add_systems(
|
||||
Update,
|
||||
(update, move_marker).run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
app.add_observer(marker_event);
|
||||
}
|
||||
|
||||
fn marker_event(
|
||||
trigger: Trigger<MarkerEvent>,
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
assets: Res<UIAssets>,
|
||||
mut sprite_params: Sprite3dParams,
|
||||
marker: Query<Entity, With<Marker>>,
|
||||
) {
|
||||
@@ -62,8 +67,6 @@ fn marker_event(
|
||||
return;
|
||||
};
|
||||
|
||||
let selector = asset_server.load("ui/selector.png");
|
||||
|
||||
let id = commands
|
||||
.spawn((
|
||||
Name::new("aim-marker"),
|
||||
@@ -71,7 +74,7 @@ fn marker_event(
|
||||
Marker,
|
||||
Transform::default(),
|
||||
Sprite3dBuilder {
|
||||
image: selector,
|
||||
image: assets.head_selector.clone(),
|
||||
pixels_per_metre: 30.,
|
||||
alpha_mode: AlphaMode::Blend,
|
||||
unlit: true,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use super::AimState;
|
||||
use crate::{
|
||||
GameState,
|
||||
backpack::BackpackHead,
|
||||
heads_ui::HeadsImages,
|
||||
loading_assets::UIAssets,
|
||||
npc::{Hitpoints, NpcHead},
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
@@ -20,15 +22,11 @@ struct TargetUi {
|
||||
}
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, (sync, update));
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(Update, (sync, update).run_if(in_state(GameState::Playing)));
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let bg = asset_server.load("ui/head_bg.png");
|
||||
let regular = asset_server.load("ui/head_regular.png");
|
||||
let damage = asset_server.load("ui/head_damage.png");
|
||||
|
||||
fn setup(mut commands: Commands, assets: Res<UIAssets>) {
|
||||
commands
|
||||
.spawn((
|
||||
Name::new("target-ui"),
|
||||
@@ -41,7 +39,12 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
},
|
||||
))
|
||||
.with_children(|parent| {
|
||||
spawn_head_ui(parent, bg.clone(), regular.clone(), damage.clone());
|
||||
spawn_head_ui(
|
||||
parent,
|
||||
assets.head_bg.clone(),
|
||||
assets.head_regular.clone(),
|
||||
assets.head_damage.clone(),
|
||||
);
|
||||
});
|
||||
|
||||
commands.insert_resource(TargetUi::default());
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use bevy::prelude::*;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::GameState;
|
||||
|
||||
pub const ALIEN_ASSET_PATH: &str = "models/alien_naked.glb";
|
||||
|
||||
#[derive(Resource)]
|
||||
@@ -10,8 +12,11 @@ pub struct Animations {
|
||||
}
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, (setup_once_loaded, toggle_animation));
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(setup_once_loaded, toggle_animation).run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
}
|
||||
|
||||
fn setup(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{BackbackSwapEvent, Backpack, BackpackHead};
|
||||
use crate::heads_ui::HeadsImages;
|
||||
use crate::{GameState, heads_ui::HeadsImages, loading_assets::UIAssets};
|
||||
use bevy::prelude::*;
|
||||
|
||||
static HEAD_SLOTS: usize = 5;
|
||||
@@ -44,20 +44,17 @@ impl BackpackUiState {
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.init_resource::<BackpackUiState>();
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(update, sync_on_change, update_visibility, update_count),
|
||||
(update, sync_on_change, update_visibility, update_count)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
|
||||
app.add_observer(swap_head_inputs);
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let bg = asset_server.load("ui/head_bg.png");
|
||||
let regular = asset_server.load("ui/head_regular.png");
|
||||
let damage = asset_server.load("ui/head_damage.png");
|
||||
let selector = asset_server.load("ui/selector.png");
|
||||
|
||||
fn setup(mut commands: Commands, assets: Res<UIAssets>) {
|
||||
commands
|
||||
.spawn((
|
||||
Name::new("backpack"),
|
||||
@@ -75,10 +72,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
for i in 0..HEAD_SLOTS {
|
||||
spawn_head_ui(
|
||||
parent,
|
||||
bg.clone(),
|
||||
regular.clone(),
|
||||
selector.clone(),
|
||||
damage.clone(),
|
||||
assets.head_bg.clone(),
|
||||
assets.head_regular.clone(),
|
||||
assets.head_selector.clone(),
|
||||
assets.head_damage.clone(),
|
||||
i,
|
||||
);
|
||||
}
|
||||
@@ -88,7 +85,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
Text::new("0"),
|
||||
BackpackCountText,
|
||||
TextFont {
|
||||
font: asset_server.load("font.ttf"),
|
||||
font: assets.font.clone(),
|
||||
font_size: 34.0,
|
||||
..default()
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mod backpack_ui;
|
||||
|
||||
use crate::heads_ui::HEAD_COUNT;
|
||||
use crate::{GameState, heads_ui::HEAD_COUNT};
|
||||
use bevy::prelude::*;
|
||||
|
||||
pub use backpack_ui::BackpackAction;
|
||||
@@ -28,7 +28,7 @@ pub struct BackbackSwapEvent(pub usize);
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_plugins(backpack_ui::plugin);
|
||||
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands) {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{control::Controls, control::controller::PlayerMovement, physics_layers::GameLayer};
|
||||
use crate::{
|
||||
GameState,
|
||||
control::{Controls, controller::PlayerMovement},
|
||||
loading_assets::UIAssets,
|
||||
physics_layers::GameLayer,
|
||||
};
|
||||
|
||||
#[derive(Component, Reflect, Debug)]
|
||||
pub struct CameraTarget;
|
||||
@@ -43,7 +48,7 @@ pub fn plugin(app: &mut App) {
|
||||
app.register_type::<MainCamera>();
|
||||
|
||||
app.init_resource::<CameraState>();
|
||||
app.add_systems(Startup, startup);
|
||||
app.add_systems(OnEnter(GameState::Playing), startup);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
@@ -52,7 +57,8 @@ pub fn plugin(app: &mut App) {
|
||||
update_look_around,
|
||||
rotate_view_keyboard,
|
||||
rotate_view_gamepad,
|
||||
),
|
||||
)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,15 +82,13 @@ fn update_look_around(controls: Res<Controls>, mut cam_state: ResMut<CameraState
|
||||
fn update_ui(
|
||||
mut commands: Commands,
|
||||
cam_state: Res<CameraState>,
|
||||
asset_server: Res<AssetServer>,
|
||||
assets: Res<UIAssets>,
|
||||
query: Query<Entity, With<CameraUi>>,
|
||||
) {
|
||||
if cam_state.is_changed() {
|
||||
let show_ui = cam_state.look_around || cam_state.cutscene;
|
||||
|
||||
if show_ui {
|
||||
let image = asset_server.load("ui/camera.png");
|
||||
|
||||
commands
|
||||
.spawn((
|
||||
CameraUi,
|
||||
@@ -102,7 +106,7 @@ fn update_ui(
|
||||
position_type: PositionType::Absolute,
|
||||
..default()
|
||||
},
|
||||
ImageNode::new(image),
|
||||
ImageNode::new(assets.camera.clone()),
|
||||
));
|
||||
} else {
|
||||
for entity in query.iter() {
|
||||
|
||||
14
src/cash.rs
14
src/cash.rs
@@ -1,7 +1,6 @@
|
||||
use crate::{GameState, loading_assets::UIAssets, sounds::PlaySound};
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::sounds::PlaySound;
|
||||
|
||||
#[derive(Component, Reflect, Default)]
|
||||
#[reflect(Component)]
|
||||
#[require(Transform)]
|
||||
@@ -21,8 +20,11 @@ pub struct CashCollectEvent;
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.init_resource::<CashResource>();
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, (rotate, update_ui));
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(rotate, update_ui).run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
app.add_observer(on_collect);
|
||||
}
|
||||
|
||||
@@ -56,12 +58,12 @@ fn update_ui(
|
||||
}
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
fn setup(mut commands: Commands, assets: Res<UIAssets>) {
|
||||
commands.spawn((
|
||||
Text::new("0"),
|
||||
CashText,
|
||||
TextFont {
|
||||
font: asset_server.load("font.ttf"),
|
||||
font: assets.font.clone(),
|
||||
font_size: 34.0,
|
||||
..default()
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use avian3d::{math::*, prelude::*};
|
||||
use bevy::{ecs::query::Has, prelude::*};
|
||||
|
||||
use crate::player::PlayerRig;
|
||||
use crate::{GameState, player::PlayerRig};
|
||||
|
||||
use super::{ControllerSet, Controls, collisions::kinematic_controller_collisions};
|
||||
|
||||
@@ -28,7 +28,8 @@ impl Plugin for CharacterControllerPlugin {
|
||||
apply_movement_damping,
|
||||
)
|
||||
.chain()
|
||||
.in_set(ControllerSet::ApplyControls),
|
||||
.in_set(ControllerSet::ApplyControls)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
app.add_systems(
|
||||
// Run collision handling after collision detection.
|
||||
@@ -36,7 +37,7 @@ impl Plugin for CharacterControllerPlugin {
|
||||
// NOTE: The collision implementation here is very basic and a bit buggy.
|
||||
// A collide-and-slide algorithm would likely work better.
|
||||
PostProcessCollisions,
|
||||
kinematic_controller_collisions,
|
||||
kinematic_controller_collisions.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{backpack::BackpackAction, heads_ui::SelectActiveHead, shooting::TriggerState};
|
||||
use crate::{
|
||||
GameState, backpack::BackpackAction, heads_ui::SelectActiveHead, shooting::TriggerState,
|
||||
};
|
||||
use bevy::{
|
||||
input::{
|
||||
ButtonState,
|
||||
@@ -22,7 +24,8 @@ pub fn plugin(app: &mut App) {
|
||||
mouse_click.run_if(on_event::<MouseButtonInput>),
|
||||
gamepad_connections.run_if(on_event::<GamepadEvent>),
|
||||
)
|
||||
.in_set(ControllerSet::CollectInputs),
|
||||
.in_set(ControllerSet::CollectInputs)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::GameState;
|
||||
|
||||
mod collisions;
|
||||
pub mod controller;
|
||||
pub mod controls;
|
||||
@@ -28,6 +30,8 @@ pub fn plugin(app: &mut App) {
|
||||
app.add_plugins(controls::plugin);
|
||||
app.configure_sets(
|
||||
Update,
|
||||
(ControllerSet::CollectInputs, ControllerSet::ApplyControls).chain(),
|
||||
(ControllerSet::CollectInputs, ControllerSet::ApplyControls)
|
||||
.chain()
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
GameState,
|
||||
camera::CameraState,
|
||||
tb_entities::{CameraTarget, CutsceneCamera, CutsceneCameraMovementEnd},
|
||||
};
|
||||
@@ -21,7 +22,7 @@ enum CutsceneState {
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.init_resource::<CutsceneState>();
|
||||
app.add_systems(Update, update);
|
||||
app.add_systems(Update, update.run_if(in_state(GameState::Playing)));
|
||||
app.add_observer(on_start_cutscene);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
GameState,
|
||||
backpack::{BackbackSwapEvent, Backpack, BackpackHead},
|
||||
loading_assets::UIAssets,
|
||||
player::head_id_to_str,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
@@ -41,18 +43,13 @@ pub struct HeadChanged(pub usize);
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.register_type::<HeadDamage>();
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, update);
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(Update, update.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>) {
|
||||
let bg = asset_server.load("ui/head_bg.png");
|
||||
let regular = asset_server.load("ui/head_regular.png");
|
||||
let damage = asset_server.load("ui/head_damage.png");
|
||||
let selector = asset_server.load("ui/selector.png");
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<UIAssets>) {
|
||||
commands
|
||||
.spawn(Node {
|
||||
position_type: PositionType::Absolute,
|
||||
@@ -65,15 +62,16 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
for i in 0..HEAD_SLOTS {
|
||||
spawn_head_ui(
|
||||
parent,
|
||||
bg.clone(),
|
||||
regular.clone(),
|
||||
selector.clone(),
|
||||
damage.clone(),
|
||||
assets.head_bg.clone(),
|
||||
assets.head_regular.clone(),
|
||||
assets.head_selector.clone(),
|
||||
assets.head_damage.clone(),
|
||||
i,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: load via asset loader
|
||||
let heads = (0usize..HEAD_COUNT)
|
||||
.map(|i| asset_server.load(format!("ui/heads/{}.png", head_id_to_str(i))))
|
||||
.collect();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
billboards::Billboard, player::Player, sounds::PlaySound, squish_animation::SquishAnimation,
|
||||
GameState, billboards::Billboard, player::Player, sounds::PlaySound,
|
||||
squish_animation::SquishAnimation,
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
@@ -16,7 +17,7 @@ struct Key(pub String);
|
||||
pub struct KeyCollected(pub String);
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Update, collect_key);
|
||||
app.add_systems(Update, collect_key.run_if(in_state(GameState::Playing)));
|
||||
app.add_observer(on_spawn);
|
||||
}
|
||||
|
||||
|
||||
51
src/loading_assets.rs
Normal file
51
src/loading_assets.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::GameState;
|
||||
use bevy::prelude::*;
|
||||
use bevy_asset_loader::prelude::*;
|
||||
|
||||
#[derive(AssetCollection, Resource)]
|
||||
pub struct AudioAssets {
|
||||
#[asset(path = "sfx/music/02.ogg")]
|
||||
pub music: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/ambient/downtown.ogg")]
|
||||
pub ambient: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/effects/key_collect.ogg")]
|
||||
pub key_collect: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/abilities/gun.ogg")]
|
||||
pub gun: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/effects/gate.ogg")]
|
||||
pub gate: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/effects/cash.ogg")]
|
||||
pub cash: Handle<AudioSource>,
|
||||
#[asset(path = "sfx/hit", collection(typed))]
|
||||
pub hit: Vec<Handle<AudioSource>>,
|
||||
}
|
||||
|
||||
#[derive(AssetCollection, Resource)]
|
||||
pub struct UIAssets {
|
||||
#[asset(path = "font.ttf")]
|
||||
pub font: Handle<Font>,
|
||||
|
||||
#[asset(path = "ui/head_bg.png")]
|
||||
pub head_bg: Handle<Image>,
|
||||
#[asset(path = "ui/head_regular.png")]
|
||||
pub head_regular: Handle<Image>,
|
||||
#[asset(path = "ui/head_damage.png")]
|
||||
pub head_damage: Handle<Image>,
|
||||
#[asset(path = "ui/selector.png")]
|
||||
pub head_selector: Handle<Image>,
|
||||
|
||||
#[asset(path = "ui/camera.png")]
|
||||
pub camera: Handle<Image>,
|
||||
}
|
||||
|
||||
pub struct LoadingPlugin;
|
||||
impl Plugin for LoadingPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_loading_state(
|
||||
LoadingState::new(GameState::AssetLoading)
|
||||
.continue_to_state(GameState::MapLoading)
|
||||
.load_collection::<AudioAssets>()
|
||||
.load_collection::<UIAssets>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
35
src/loading_map.rs
Normal file
35
src/loading_map.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use crate::{GameState, physics_layers::GameLayer};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::{prelude::*, scene::SceneInstanceReady};
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(OnEnter(GameState::MapLoading), setup_scene);
|
||||
}
|
||||
|
||||
fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands
|
||||
.spawn((
|
||||
CollisionLayers::new(LayerMask(GameLayer::Level.to_bits()), LayerMask::ALL),
|
||||
SceneRoot(asset_server.load("maps/map1.map#Scene")),
|
||||
))
|
||||
.observe(
|
||||
|_t: Trigger<SceneInstanceReady>, mut next_game_state: ResMut<NextState<GameState>>| {
|
||||
info!("map loaded");
|
||||
|
||||
next_game_state.set(GameState::Playing);
|
||||
},
|
||||
);
|
||||
|
||||
commands.spawn((
|
||||
DirectionalLight {
|
||||
illuminance: light_consts::lux::OVERCAST_DAY,
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
Transform {
|
||||
translation: Vec3::new(0.0, 2.0, 0.0),
|
||||
rotation: Quat::from_rotation_x(-1.7),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
57
src/main.rs
57
src/main.rs
@@ -1,7 +1,6 @@
|
||||
mod aim;
|
||||
mod alien;
|
||||
mod backpack;
|
||||
mod billboards;
|
||||
mod camera;
|
||||
mod cash;
|
||||
mod control;
|
||||
@@ -9,6 +8,8 @@ mod cutscene;
|
||||
mod gates;
|
||||
mod heads_ui;
|
||||
mod keys;
|
||||
mod loading_assets;
|
||||
mod loading_map;
|
||||
mod movables;
|
||||
mod npc;
|
||||
mod physics_layers;
|
||||
@@ -16,8 +17,8 @@ mod platforms;
|
||||
mod player;
|
||||
mod shooting;
|
||||
mod sounds;
|
||||
mod squish_animation;
|
||||
mod tb_entities;
|
||||
mod utils;
|
||||
|
||||
use avian3d::prelude::*;
|
||||
use bevy::audio::PlaybackMode;
|
||||
@@ -25,12 +26,13 @@ use bevy::audio::Volume;
|
||||
use bevy::core_pipeline::tonemapping::Tonemapping;
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::view::ColorGrading;
|
||||
use bevy::scene::SceneInstanceReady;
|
||||
use bevy_polyline::PolylinePlugin;
|
||||
use bevy_sprite3d::Sprite3dPlugin;
|
||||
use bevy_trenchbroom::prelude::*;
|
||||
use control::controller::CharacterControllerPlugin;
|
||||
use physics_layers::GameLayer;
|
||||
use loading_assets::AudioAssets;
|
||||
use utils::billboards;
|
||||
use utils::squish_animation;
|
||||
|
||||
#[derive(Resource, Reflect, Debug)]
|
||||
#[reflect(Resource)]
|
||||
@@ -42,6 +44,14 @@ struct DebugVisuals {
|
||||
pub cam_follow: bool,
|
||||
}
|
||||
|
||||
#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)]
|
||||
enum GameState {
|
||||
#[default]
|
||||
AssetLoading,
|
||||
MapLoading,
|
||||
Playing,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut app = App::new();
|
||||
|
||||
@@ -100,6 +110,10 @@ fn main() {
|
||||
app.add_plugins(sounds::plugin);
|
||||
app.add_plugins(camera::plugin);
|
||||
app.add_plugins(backpack::plugin);
|
||||
app.add_plugins(loading_assets::LoadingPlugin);
|
||||
app.add_plugins(loading_map::plugin);
|
||||
|
||||
app.init_state::<GameState>();
|
||||
|
||||
app.insert_resource(AmbientLight {
|
||||
color: Color::WHITE,
|
||||
@@ -107,41 +121,16 @@ fn main() {
|
||||
});
|
||||
app.insert_resource(ClearColor(Color::BLACK));
|
||||
|
||||
app.add_systems(Startup, (write_trenchbroom_config, music));
|
||||
app.add_systems(PostStartup, setup_scene);
|
||||
app.add_systems(Startup, write_trenchbroom_config);
|
||||
app.add_systems(OnEnter(GameState::Playing), music);
|
||||
app.add_systems(Update, (set_materials_unlit, set_tonemapping, set_shadows));
|
||||
|
||||
app.run();
|
||||
}
|
||||
|
||||
fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands
|
||||
.spawn((
|
||||
CollisionLayers::new(LayerMask(GameLayer::Level.to_bits()), LayerMask::ALL),
|
||||
SceneRoot(asset_server.load("maps/map1.map#Scene")),
|
||||
))
|
||||
.observe(|_t: Trigger<SceneInstanceReady>| {
|
||||
//TODO: use for state driven map loading
|
||||
info!("map loaded");
|
||||
});
|
||||
|
||||
fn music(assets: Res<AudioAssets>, mut commands: Commands) {
|
||||
commands.spawn((
|
||||
DirectionalLight {
|
||||
illuminance: light_consts::lux::OVERCAST_DAY,
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
Transform {
|
||||
translation: Vec3::new(0.0, 2.0, 0.0),
|
||||
rotation: Quat::from_rotation_x(-1.7),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
fn music(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
commands.spawn((
|
||||
AudioPlayer::new(asset_server.load("sfx/music/02.ogg")),
|
||||
AudioPlayer::new(assets.music.clone()),
|
||||
PlaybackSettings {
|
||||
mode: PlaybackMode::Loop,
|
||||
volume: Volume::new(0.6),
|
||||
@@ -150,7 +139,7 @@ fn music(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
));
|
||||
|
||||
commands.spawn((
|
||||
AudioPlayer::new(asset_server.load("sfx/ambient/downtown.ogg")),
|
||||
AudioPlayer::new(assets.ambient.clone()),
|
||||
PlaybackSettings {
|
||||
mode: PlaybackMode::Loop,
|
||||
volume: Volume::new(1.),
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::tb_entities::{Movable, MoveTarget};
|
||||
use crate::{
|
||||
GameState,
|
||||
tb_entities::{Movable, MoveTarget},
|
||||
};
|
||||
use bevy::{prelude::*, utils::HashSet};
|
||||
use bevy_trenchbroom::class::Target;
|
||||
|
||||
@@ -16,7 +19,7 @@ pub struct TriggerMovableEvent(pub HashSet<String>);
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.register_type::<ActiveMovable>();
|
||||
app.add_systems(Update, move_active);
|
||||
app.add_systems(Update, move_active.run_if(in_state(GameState::Playing)));
|
||||
app.add_observer(trigger);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
heads_ui::HEAD_COUNT, keys::KeySpawn, player::head_id_to_str, sounds::PlaySound,
|
||||
GameState, heads_ui::HEAD_COUNT, keys::KeySpawn, player::head_id_to_str, sounds::PlaySound,
|
||||
tb_entities::EnemySpawn,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Event, Reflect)]
|
||||
pub struct Hit {
|
||||
@@ -31,10 +30,9 @@ impl Hitpoints {
|
||||
pub struct NpcHead(pub usize);
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Update, init);
|
||||
app.add_systems(OnEnter(GameState::Playing), init);
|
||||
}
|
||||
|
||||
// TODO: use game state to initialize only once
|
||||
fn init(mut commands: Commands, query: Query<(Entity, &EnemySpawn), Without<Hitpoints>>) {
|
||||
let mut names: HashMap<String, usize> = HashMap::default();
|
||||
for i in 0..HEAD_COUNT {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::tb_entities::{Platform, PlatformTarget};
|
||||
use crate::{
|
||||
GameState,
|
||||
tb_entities::{Platform, PlatformTarget},
|
||||
};
|
||||
use bevy::{math::ops::sin, prelude::*};
|
||||
use bevy_trenchbroom::class::Target;
|
||||
|
||||
@@ -11,7 +14,8 @@ struct ActivePlatform {
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.register_type::<ActivePlatform>();
|
||||
app.add_systems(Update, (init, move_active));
|
||||
app.add_systems(OnEnter(GameState::Playing), init);
|
||||
app.add_systems(Update, move_active.run_if(in_state(GameState::Playing)));
|
||||
}
|
||||
|
||||
fn init(
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use crate::{
|
||||
GameState,
|
||||
alien::{ALIEN_ASSET_PATH, Animations},
|
||||
camera::{CameraArmRotation, CameraTarget},
|
||||
cash::{Cash, CashCollectEvent},
|
||||
control::Controls,
|
||||
control::controller::{CharacterControllerBundle, PlayerMovement},
|
||||
control::{
|
||||
Controls,
|
||||
controller::{CharacterControllerBundle, PlayerMovement},
|
||||
},
|
||||
heads_ui::HeadChanged,
|
||||
physics_layers::GameLayer,
|
||||
tb_entities::SpawnPoint,
|
||||
@@ -40,18 +43,22 @@ struct PlayerSpawned {
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.init_resource::<PlayerSpawned>();
|
||||
app.add_systems(Startup, (toggle_cursor_system, cursor_recenter));
|
||||
app.add_systems(OnEnter(GameState::Playing), spawn);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
spawn,
|
||||
collect_cash,
|
||||
toggle_animation,
|
||||
setup_animations_marker_for_player,
|
||||
toggle_cursor_system.run_if(input_just_pressed(KeyCode::Escape)),
|
||||
),
|
||||
)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
|
||||
app.add_systems(Update, (rotate_view_keyboard, rotate_view_gamepad));
|
||||
app.add_systems(
|
||||
Update,
|
||||
(rotate_view_keyboard, rotate_view_gamepad).run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
|
||||
app.add_observer(update_head);
|
||||
}
|
||||
@@ -259,6 +266,7 @@ fn update_head(
|
||||
|
||||
let head_str = head_id_to_str(trigger.0);
|
||||
|
||||
//TODO: use asset loader
|
||||
commands.spawn((
|
||||
AudioPlayer::new(asset_server.load(format!("sfx/heads/{}.ogg", head_str))),
|
||||
PlaybackSettings::DESPAWN,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
GameState,
|
||||
aim::AimState,
|
||||
billboards::Billboard,
|
||||
npc::Hit,
|
||||
@@ -39,10 +40,11 @@ struct ShotAssets {
|
||||
struct AnimationTimer(Timer);
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||
app.add_systems(
|
||||
Update,
|
||||
(update, shot_collision, enemy_hit, timeout, animate_sprite),
|
||||
(update, shot_collision, enemy_hit, timeout, animate_sprite)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
);
|
||||
app.add_observer(on_trigger_state);
|
||||
}
|
||||
@@ -52,6 +54,7 @@ fn setup(
|
||||
asset_server: Res<AssetServer>,
|
||||
mut sprite_params: Sprite3dParams,
|
||||
) {
|
||||
// TODO: use asset server
|
||||
let image = asset_server.load("textures/fx/impact.png");
|
||||
let layout = TextureAtlasLayout::from_grid(UVec2::splat(256), 7, 6, None, None);
|
||||
let texture_atlas_layout = sprite_params.atlas_layouts.add(layout);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::loading_assets::AudioAssets;
|
||||
|
||||
#[derive(Event, Copy, Clone, Debug)]
|
||||
pub enum PlaySound {
|
||||
Hit,
|
||||
@@ -18,7 +20,7 @@ fn spawn_sounds(
|
||||
mut commands: Commands,
|
||||
// sound_res: Res<AudioAssets>,
|
||||
// settings: SettingsRead,
|
||||
asset_server: Res<AssetServer>,
|
||||
assets: Res<AudioAssets>,
|
||||
) {
|
||||
let event = trigger.event();
|
||||
|
||||
@@ -29,12 +31,12 @@ fn spawn_sounds(
|
||||
let source = match event {
|
||||
PlaySound::Hit => {
|
||||
let version = rand::random::<u8>() % 3;
|
||||
asset_server.load(format!("sfx/hit/hit_0{version}.ogg"))
|
||||
assets.hit[version as usize].clone()
|
||||
}
|
||||
PlaySound::KeyCollect => asset_server.load("sfx/effects/key_collect.ogg"),
|
||||
PlaySound::Gun => asset_server.load("sfx/abilities/gun.ogg"),
|
||||
PlaySound::Gate => asset_server.load("sfx/effects/gate.ogg"),
|
||||
PlaySound::CashCollect => asset_server.load("sfx/effects/cash.ogg"),
|
||||
PlaySound::KeyCollect => assets.key_collect.clone(),
|
||||
PlaySound::Gun => assets.gun.clone(),
|
||||
PlaySound::Gate => assets.gate.clone(),
|
||||
PlaySound::CashCollect => assets.cash.clone(),
|
||||
};
|
||||
|
||||
commands.spawn((
|
||||
|
||||
@@ -22,7 +22,10 @@ fn face_camera(
|
||||
>,
|
||||
parent_transform: Query<&GlobalTransform>,
|
||||
) {
|
||||
let cam_transform = cam_query.single();
|
||||
let Ok(cam_transform) = cam_query.get_single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (mut transform, parent, visible) in query.iter_mut() {
|
||||
if !matches!(*visible, InheritedVisibility::VISIBLE) {
|
||||
continue;
|
||||
@@ -41,7 +44,9 @@ fn face_camera_no_parent(
|
||||
cam_query: Query<&GlobalTransform, With<Camera>>,
|
||||
mut query: Query<&mut Transform, (With<Billboard>, Without<Camera>, Without<Parent>)>,
|
||||
) {
|
||||
let cam_transform = cam_query.single();
|
||||
let Ok(cam_transform) = cam_query.get_single() else {
|
||||
return;
|
||||
};
|
||||
for mut transform in query.iter_mut() {
|
||||
transform.look_at(cam_transform.translation(), Vec3::Y);
|
||||
}
|
||||
2
src/utils/mod.rs
Normal file
2
src/utils/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod billboards;
|
||||
pub mod squish_animation;
|
||||
Reference in New Issue
Block a user