You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.2 KiB
Rust
158 lines
4.2 KiB
Rust
mod blocks;
|
|
mod debug;
|
|
mod fighter;
|
|
|
|
use engine::*;
|
|
use serde::Deserialize;
|
|
use thiserror::Error;
|
|
|
|
use blocks::*;
|
|
use debug::*;
|
|
use fighter::*;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_plugins(FeathersPlugins)
|
|
.add_plugins((BlocksPlugin, FighterPlugin, DebugPlugin))
|
|
.init_state::<Loading>()
|
|
.init_state::<GameState>()
|
|
.init_resource::<AllAssets>()
|
|
.init_resource::<SetupChecklist>()
|
|
// Check if assets were added to loading queue
|
|
.add_systems(
|
|
Update,
|
|
loading_check
|
|
.run_if(in_state(Loading(true)))
|
|
.run_if(resource_changed::<AllAssets>),
|
|
)
|
|
// Wait for pending assets to be loaded
|
|
.add_systems(Update, loading_wait.run_if(in_state(Loading(true))))
|
|
// Once done loading, move to the setup state
|
|
.add_systems(OnEnter(Loading(false)), setup_game)
|
|
// Check if the game is ready to progress
|
|
.add_systems(Update, setup_wait.run_if(in_state(GameState::Setup)))
|
|
// State toggles
|
|
.add_systems(Update, (
|
|
(
|
|
toggle_state_visibility::<Loading>,
|
|
sync_state_to_ui::<Loading>,
|
|
).run_if(state_changed::<Loading>),
|
|
(
|
|
toggle_state_visibility::<GameState>,
|
|
sync_state_to_ui::<GameState>,
|
|
).run_if(state_changed::<GameState>)
|
|
))
|
|
.run();
|
|
}
|
|
|
|
/// Reports if the game is loading assets
|
|
#[derive(States, Clone, Eq, Debug, PartialEq, Hash, Component)]
|
|
struct Loading(bool);
|
|
|
|
impl Default for Loading {
|
|
fn default() -> Self {
|
|
Loading(true)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Loading {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Loading {}", self.0)
|
|
}
|
|
}
|
|
|
|
/// Tracks what state the main game loop is in
|
|
#[derive(States, Default, Clone, Eq, Debug, PartialEq, Hash, Component)]
|
|
enum GameState {
|
|
#[default]
|
|
Boot,
|
|
Setup,
|
|
Run,
|
|
}
|
|
|
|
impl fmt::Display for GameState {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
GameState::Boot => write!(f, "Game State: Boot"),
|
|
GameState::Setup => write!(f, "GameState: Setup"),
|
|
GameState::Run => write!(f, "GameState: Run"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A list of all assets so we don't lose them
|
|
#[derive(Default, Resource, Debug)]
|
|
struct AllAssets {
|
|
handles: Vec<UntypedHandle>,
|
|
}
|
|
|
|
/// A "checklist" to know if we can progress from setup to the game
|
|
#[derive(Default, Resource)]
|
|
struct SetupChecklist {
|
|
spawn_shape: bool,
|
|
}
|
|
|
|
impl SetupChecklist {
|
|
fn done(&self) -> bool {
|
|
self.spawn_shape
|
|
}
|
|
}
|
|
|
|
/// Sends the game into Loading::Active if assets are added to the AllAssets list
|
|
fn loading_check(mut next: ResMut<NextState<Loading>>, all_assets: Res<AllAssets>) {
|
|
debug_assert!(all_assets.is_changed());
|
|
|
|
next.set(Loading(true));
|
|
}
|
|
|
|
/// Waits in Loading::Active until all assets are loaded then move to Loading(false)
|
|
fn loading_wait(
|
|
curr: Res<State<Loading>>,
|
|
mut next: ResMut<NextState<Loading>>,
|
|
server: Res<AssetServer>,
|
|
all_assets: Res<AllAssets>,
|
|
) {
|
|
debug_assert!(*curr.get() == Loading(true));
|
|
if all_assets
|
|
.handles
|
|
.iter()
|
|
.all(|h| matches!(server.get_load_state(h.id()), Some(LoadState::Loaded)))
|
|
{
|
|
next.set(Loading(false));
|
|
}
|
|
}
|
|
|
|
/// Moves the game from Boot to Setup
|
|
fn setup_game(curr: Res<State<GameState>>, mut next: ResMut<NextState<GameState>>) {
|
|
debug_assert!(*curr.get() == GameState::Boot);
|
|
|
|
next.set(GameState::Setup);
|
|
}
|
|
|
|
/// Wait until all checklist items are complete
|
|
fn setup_wait(
|
|
curr: Res<State<GameState>>,
|
|
mut next: ResMut<NextState<GameState>>,
|
|
checklist: Res<SetupChecklist>,
|
|
) {
|
|
debug_assert!(*curr.get() == GameState::Setup);
|
|
|
|
// If all checks pass, move on to the run state
|
|
if checklist.done() {
|
|
next.set(GameState::Run);
|
|
}
|
|
}
|
|
|
|
/// A wrapper around a handle for assigning an arbitrary Handle<T> to an entity
|
|
#[derive(Debug, Component)]
|
|
struct AssetComponent<T: Asset> {
|
|
handle: Handle<T>,
|
|
}
|
|
|
|
impl<T: Asset> AssetComponent<T> {
|
|
fn new(handle: Handle<T>) -> Self {
|
|
Self { handle }
|
|
}
|
|
}
|