Make stages data-driven
This commit is contained in:
@@ -14,6 +14,9 @@
|
|||||||
ground_max_horizontal_velocity: "3.0",
|
ground_max_horizontal_velocity: "3.0",
|
||||||
ground_friction_over_walk_speed_multiplier: "2.0"
|
ground_friction_over_walk_speed_multiplier: "2.0"
|
||||||
),
|
),
|
||||||
|
stage_manifest_paths: [
|
||||||
|
"stages/test.stage.ron"
|
||||||
|
],
|
||||||
fighter_manifest_paths: [
|
fighter_manifest_paths: [
|
||||||
"fighters/test/test.fighter.ron"
|
"fighters/test/test.fighter.ron"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
(
|
||||||
|
id: TestStage,
|
||||||
|
model_path: "stages/battlefield.glb#Scene0",
|
||||||
|
polygons: [
|
||||||
|
(
|
||||||
|
poly_type: Platform,
|
||||||
|
lines: [
|
||||||
|
(
|
||||||
|
(x: "-59.5", y: "23.45"),
|
||||||
|
Floor
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "-28.0", y: "23.45"),
|
||||||
|
Floor
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
poly_type: Platform,
|
||||||
|
lines: [
|
||||||
|
(
|
||||||
|
(x: "28.0", y: "23.45"),
|
||||||
|
Floor
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "59.5", y: "23.45"),
|
||||||
|
Floor
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
poly_type: Closed,
|
||||||
|
lines: [
|
||||||
|
(
|
||||||
|
(x: "-56", y: "-200.0"),
|
||||||
|
Wall
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "-56.0", y: "-3.5"),
|
||||||
|
Floor,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "-39.2", y: "0.0"),
|
||||||
|
Floor,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "0.0", y: "0.0"),
|
||||||
|
Floor
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "39.2", y: "0.0"),
|
||||||
|
Floor
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "56.0", y: "-3.5"),
|
||||||
|
Wall
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(x: "56", y: "-200.0"),
|
||||||
|
Wall
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -113,7 +113,7 @@ pub fn prepare_fighter_manifests(
|
|||||||
}
|
}
|
||||||
|
|
||||||
commands.insert_resource(FighterManifestRegistry(registry));
|
commands.insert_resource(FighterManifestRegistry(registry));
|
||||||
next_state.set(AppState::Idle);
|
next_state.set(AppState::LoadStageManifests);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fail(next_state: &mut NextState<AppState>, message: &str) {
|
fn fail(next_state: &mut NextState<AppState>, message: &str) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub struct GameSettings {
|
|||||||
pub fighter_common: FighterSettingsCommon,
|
pub fighter_common: FighterSettingsCommon,
|
||||||
pub input_common: InputSettingsCommon,
|
pub input_common: InputSettingsCommon,
|
||||||
pub fighter_manifest_paths: Vec<String>,
|
pub fighter_manifest_paths: Vec<String>,
|
||||||
|
pub stage_manifest_paths: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(AssetCollection, Resource)]
|
#[derive(AssetCollection, Resource)]
|
||||||
|
|||||||
+14
-2
@@ -28,8 +28,7 @@ use clap::Parser;
|
|||||||
use jackdaw_runtime::EditorCategory;
|
use jackdaw_runtime::EditorCategory;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::manifest::FighterManifest, game_settings::GameSettings,
|
fighter::manifest::FighterManifest, game_settings::GameSettings, schedule::GameplaySchedulePlugin, stage::manifest::{StageManifest, StageManifestAssets},
|
||||||
schedule::GameplaySchedulePlugin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
@@ -49,6 +48,8 @@ pub enum AppState {
|
|||||||
LoadCommonAssets,
|
LoadCommonAssets,
|
||||||
LoadFighterManifests,
|
LoadFighterManifests,
|
||||||
PrepareFighterManifests,
|
PrepareFighterManifests,
|
||||||
|
LoadStageManifests,
|
||||||
|
PrepareStageManifests,
|
||||||
CommonAssetLoadFailed,
|
CommonAssetLoadFailed,
|
||||||
Idle,
|
Idle,
|
||||||
LoadingMatch,
|
LoadingMatch,
|
||||||
@@ -78,6 +79,7 @@ impl Plugin for GamePlugin {
|
|||||||
fighter::FighterPlugin,
|
fighter::FighterPlugin,
|
||||||
stage::StagePlugin,
|
stage::StagePlugin,
|
||||||
bevy_common_assets::ron::RonAssetPlugin::<FighterManifest>::new(&["fighter.ron"]),
|
bevy_common_assets::ron::RonAssetPlugin::<FighterManifest>::new(&["fighter.ron"]),
|
||||||
|
bevy_common_assets::ron::RonAssetPlugin::<StageManifest>::new(&["stage.ron"]),
|
||||||
bevy_common_assets::ron::RonAssetPlugin::<GameSettings>::new(&["ron"]),
|
bevy_common_assets::ron::RonAssetPlugin::<GameSettings>::new(&["ron"]),
|
||||||
))
|
))
|
||||||
.add_loading_state(
|
.add_loading_state(
|
||||||
@@ -99,10 +101,20 @@ impl Plugin for GamePlugin {
|
|||||||
.on_failure_continue_to_state(AppState::CommonAssetLoadFailed)
|
.on_failure_continue_to_state(AppState::CommonAssetLoadFailed)
|
||||||
.load_collection::<fighter::manifest::FighterManifestAssets>(),
|
.load_collection::<fighter::manifest::FighterManifestAssets>(),
|
||||||
)
|
)
|
||||||
|
.add_loading_state(
|
||||||
|
LoadingState::new(AppState::LoadStageManifests)
|
||||||
|
.continue_to_state(AppState::PrepareStageManifests)
|
||||||
|
.on_failure_continue_to_state(AppState::CommonAssetLoadFailed)
|
||||||
|
.load_collection::<stage::manifest::StageManifestAssets>(),
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
OnEnter(AppState::PrepareFighterManifests),
|
OnEnter(AppState::PrepareFighterManifests),
|
||||||
fighter::manifest::prepare_fighter_manifests,
|
fighter::manifest::prepare_fighter_manifests,
|
||||||
)
|
)
|
||||||
|
.add_systems(
|
||||||
|
OnEnter(AppState::PrepareStageManifests),
|
||||||
|
stage::manifest::prepare_stage_manifests,
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
OnEnter(AppState::Idle),
|
OnEnter(AppState::Idle),
|
||||||
match_loading::initiate_default_match,
|
match_loading::initiate_default_match,
|
||||||
|
|||||||
+22
-18
@@ -18,22 +18,12 @@ use crate::{
|
|||||||
},
|
},
|
||||||
math::{int::FGi32, vec::FGVec2},
|
math::{int::FGi32, vec::FGVec2},
|
||||||
netcode::{GGRSCfg, session::create_session},
|
netcode::{GGRSCfg, session::create_session},
|
||||||
stage,
|
stage::{
|
||||||
|
self,
|
||||||
|
manifest::{StageId, StageManifest, StageManifestRegistry},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub enum StageId {
|
|
||||||
Battlefield,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StageId {
|
|
||||||
fn scene_path(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Battlefield => "stages/battlefield.glb#Scene0",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MatchPlayer {
|
pub struct MatchPlayer {
|
||||||
pub handle: usize,
|
pub handle: usize,
|
||||||
@@ -62,10 +52,19 @@ impl MatchAssets {
|
|||||||
let request = world.resource::<PendingMatch>();
|
let request = world.resource::<PendingMatch>();
|
||||||
let asset_server = world.resource::<AssetServer>();
|
let asset_server = world.resource::<AssetServer>();
|
||||||
let registry = world.resource::<FighterManifestRegistry>();
|
let registry = world.resource::<FighterManifestRegistry>();
|
||||||
|
let stage_registry = world.resource::<StageManifestRegistry>();
|
||||||
let manifests = world.resource::<Assets<FighterManifest>>();
|
let manifests = world.resource::<Assets<FighterManifest>>();
|
||||||
|
let stage_manifests = world.resource::<Assets<StageManifest>>();
|
||||||
|
|
||||||
|
let stage_handle = stage_registry
|
||||||
|
.get(request.stage)
|
||||||
|
.expect("Startup validation guarantees every stage has a manifest");
|
||||||
|
let stage_manifest = stage_manifests
|
||||||
|
.get(&stage_handle)
|
||||||
|
.expect("startup-loaded stage manifest should remain available");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
stage: asset_server.load(request.stage.scene_path()),
|
stage: asset_server.load(stage_manifest.model_path.clone()),
|
||||||
fighters: request
|
fighters: request
|
||||||
.players
|
.players
|
||||||
.iter()
|
.iter()
|
||||||
@@ -131,7 +130,7 @@ pub fn initiate_default_match(
|
|||||||
&mut commands,
|
&mut commands,
|
||||||
&mut next_state,
|
&mut next_state,
|
||||||
PendingMatch {
|
PendingMatch {
|
||||||
stage: StageId::Battlefield,
|
stage: StageId::TestStage,
|
||||||
players,
|
players,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -143,7 +142,9 @@ pub fn prepare_match(
|
|||||||
assets: Res<MatchAssets>,
|
assets: Res<MatchAssets>,
|
||||||
gltfs: Res<Assets<Gltf>>,
|
gltfs: Res<Assets<Gltf>>,
|
||||||
registry: Res<FighterManifestRegistry>,
|
registry: Res<FighterManifestRegistry>,
|
||||||
|
stage_registry: Res<StageManifestRegistry>,
|
||||||
manifests: Res<Assets<FighterManifest>>,
|
manifests: Res<Assets<FighterManifest>>,
|
||||||
|
stage_manifests: Res<Assets<StageManifest>>,
|
||||||
mut graphs: ResMut<Assets<AnimationGraph>>,
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
||||||
args: Res<Args>,
|
args: Res<Args>,
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
@@ -231,7 +232,10 @@ pub fn prepare_match(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let root = commands.spawn((Name::new("Match"), MatchRoot)).id();
|
let root = commands.spawn((Name::new("Match"), MatchRoot)).id();
|
||||||
stage::spawn_stage(&mut commands, root, assets.stage.clone());
|
|
||||||
|
let stage_handle = stage_registry.get(request.stage).expect("Initialization check should ensure all stages exist");
|
||||||
|
let stage_manifest = stage_manifests.get(&stage_handle).expect("Initialization check should ensure stage manifests are kept alive");
|
||||||
|
stage::spawn_stage(&mut commands, root, assets.stage.clone(), stage_manifest.to_collision());
|
||||||
|
|
||||||
for (index, (player, (scene, animations, attributes))) in
|
for (index, (player, (scene, animations, attributes))) in
|
||||||
request.players.iter().zip(prepared).enumerate()
|
request.players.iter().zip(prepared).enumerate()
|
||||||
@@ -289,7 +293,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn match_request_keeps_duplicate_fighter_slots() {
|
fn match_request_keeps_duplicate_fighter_slots() {
|
||||||
let request = PendingMatch {
|
let request = PendingMatch {
|
||||||
stage: StageId::Battlefield,
|
stage: StageId::TestStage,
|
||||||
players: vec![
|
players: vec![
|
||||||
MatchPlayer {
|
MatchPlayer {
|
||||||
handle: 0,
|
handle: 0,
|
||||||
|
|||||||
+4
-4
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::math::{segment::FGSegment2d, vec::FGVec2};
|
use crate::math::{segment::FGSegment2d, vec::FGVec2};
|
||||||
|
|
||||||
#[derive(Reflect, Clone, Copy, PartialEq)]
|
#[derive(Reflect, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum StagePolyLineSegmentType {
|
pub enum StagePolyLineSegmentType {
|
||||||
Floor,
|
Floor,
|
||||||
Wall,
|
Wall,
|
||||||
@@ -19,7 +20,7 @@ pub struct StagePolyLineSegment {
|
|||||||
pub segment_type: StagePolyLineSegmentType,
|
pub segment_type: StagePolyLineSegmentType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Reflect, Clone, Default)]
|
#[derive(Reflect, Clone, Default, Serialize, Deserialize, Copy)]
|
||||||
pub enum StagePolyType {
|
pub enum StagePolyType {
|
||||||
#[default]
|
#[default]
|
||||||
Closed,
|
Closed,
|
||||||
@@ -32,8 +33,7 @@ pub struct StageLineID {
|
|||||||
pub segment: usize,
|
pub segment: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Reflect, Clone, Default)]
|
#[derive(Reflect, Clone, Default)]
|
||||||
#[reflect(Component)]
|
|
||||||
pub struct StagePoly {
|
pub struct StagePoly {
|
||||||
poly_type: StagePolyType,
|
poly_type: StagePolyType,
|
||||||
pub segments: Vec<StagePolyLineSegment>,
|
pub segments: Vec<StagePolyLineSegment>,
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use bevy_asset_loader::asset_collection::AssetCollection;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum_macros::{EnumIter};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
AppState, game_settings::GameSettings, math::{int::FGi32, vec::FGVec2}, stage::{StagePoly, line::{StageCollision, StagePolyLineSegmentType, StagePolyType}},
|
||||||
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Reflect, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash, Debug, EnumIter)]
|
||||||
|
pub enum StageId {
|
||||||
|
TestStage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Reflect)]
|
||||||
|
#[reflect(opaque)]
|
||||||
|
pub struct StagePolyDefinition {
|
||||||
|
poly_type: StagePolyType,
|
||||||
|
lines: Vec<(FGVec2, StagePolyLineSegmentType)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Asset, Reflect)]
|
||||||
|
pub struct StageManifest {
|
||||||
|
pub id: StageId,
|
||||||
|
pub model_path: String,
|
||||||
|
pub polygons: Vec<StagePolyDefinition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct StageManifestAssets(pub Vec<Handle<StageManifest>>);
|
||||||
|
|
||||||
|
impl StageManifestAssets {
|
||||||
|
fn requested(world: &World) -> Self {
|
||||||
|
let settings = world.resource::<GameSettings>();
|
||||||
|
let asset_server = world.resource::<AssetServer>();
|
||||||
|
|
||||||
|
Self(
|
||||||
|
settings
|
||||||
|
.stage_manifest_paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| asset_server.load(path.clone()))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetCollection for StageManifestAssets {
|
||||||
|
fn create(world: &mut World) -> Self {
|
||||||
|
Self::requested(world)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(world: &mut World) -> Vec<UntypedHandle> {
|
||||||
|
Self::requested(world)
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.map(Handle::untyped)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct StageManifestRegistry(HashMap<StageId, Handle<StageManifest>>);
|
||||||
|
|
||||||
|
impl StageManifestRegistry {
|
||||||
|
pub fn get(&self, stage: StageId) -> Option<Handle<StageManifest>> {
|
||||||
|
self.0.get(&stage).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail(next_state: &mut NextState<AppState>, message: &str) {
|
||||||
|
error!("Stage manifest preparation failed: {message}");
|
||||||
|
next_state.set(AppState::CommonAssetLoadFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn prepare_stage_manifests(
|
||||||
|
mut commands: Commands,
|
||||||
|
handles: Res<StageManifestAssets>,
|
||||||
|
manifests: Res<Assets<StageManifest>>,
|
||||||
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
|
) {
|
||||||
|
let mut registry = HashMap::with_capacity(handles.0.len());
|
||||||
|
|
||||||
|
for handle in &handles.0 {
|
||||||
|
let Some(manifest) = manifests.get(handle) else {
|
||||||
|
fail(&mut next_state, "a loaded fighter manifest is unavailable");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if manifest.model_path.is_empty() {
|
||||||
|
fail(
|
||||||
|
&mut next_state,
|
||||||
|
&format!("{:?} has an empty model path", manifest.id),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if registry.insert(manifest.id, handle.clone()).is_some() {
|
||||||
|
fail(
|
||||||
|
&mut next_state,
|
||||||
|
&format!("duplicate manifest for stage {:?}", manifest.id),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for stage in StageId::iter() {
|
||||||
|
if !registry.contains_key(&stage) {
|
||||||
|
fail(
|
||||||
|
&mut next_state,
|
||||||
|
&format!("no manifest configured for stage {stage:?}"),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.insert_resource(StageManifestRegistry(registry));
|
||||||
|
next_state.set(AppState::Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StageManifest {
|
||||||
|
pub fn to_collision(&self) -> StageCollision {
|
||||||
|
let stage_polys: Vec<StagePoly> = self.polygons.iter().map(|def| {
|
||||||
|
StagePoly::build(def.poly_type, &def.lines)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
StageCollision {
|
||||||
|
stage_polys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -6,9 +6,12 @@ use bevy::prelude::*;
|
|||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod line;
|
pub mod line;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
|
pub mod manifest;
|
||||||
|
|
||||||
pub use line::{StagePlaneIntersectResult, StagePoly};
|
pub use line::{StagePlaneIntersectResult, StagePoly};
|
||||||
|
|
||||||
|
use crate::stage::line::StageCollision;
|
||||||
|
|
||||||
/// Owns the stage geometry: which scene gets spawned and how it is drawn.
|
/// Owns the stage geometry: which scene gets spawned and how it is drawn.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct StagePlugin;
|
pub struct StagePlugin;
|
||||||
@@ -22,7 +25,7 @@ impl Plugin for StagePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_stage(commands: &mut Commands, match_root: Entity, visual: Handle<WorldAsset>) {
|
pub fn spawn_stage(commands: &mut Commands, match_root: Entity, visual: Handle<WorldAsset>, collision: StageCollision) {
|
||||||
commands.entity(match_root).insert(WorldAssetRoot(visual));
|
commands.entity(match_root).insert(WorldAssetRoot(visual));
|
||||||
scene::spawn_stage_support(commands, match_root);
|
scene::spawn_stage_support(commands, match_root, collision);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-30
@@ -3,43 +3,17 @@
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
math::vec::FGVec2,
|
math::{int::FGi32, vec::FGVec2}, stage::{
|
||||||
stage::{
|
|
||||||
StagePoly,
|
StagePoly,
|
||||||
line::{StageCollision, StagePolyLineSegmentType, StagePolyType},
|
line::{StageCollision, StagePolyLineSegmentType, StagePolyType},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn spawn_stage_support(commands: &mut Commands, match_root: Entity) {
|
pub fn spawn_stage_support(commands: &mut Commands, match_root: Entity, collision: StageCollision) {
|
||||||
let stage_poly = StagePoly::build(
|
commands.insert_resource(collision);
|
||||||
StagePolyType::Closed,
|
|
||||||
&[
|
|
||||||
(
|
|
||||||
FGVec2::lit("-56.0", "-3.5"),
|
|
||||||
StagePolyLineSegmentType::Floor,
|
|
||||||
),
|
|
||||||
(FGVec2::lit("-39.2", "0.0"), StagePolyLineSegmentType::Floor),
|
|
||||||
(FGVec2::lit("0.0", "0.0"), StagePolyLineSegmentType::Floor),
|
|
||||||
(FGVec2::lit("39.2", "0.0"), StagePolyLineSegmentType::Floor),
|
|
||||||
(FGVec2::lit("56.0", "-3.5"), StagePolyLineSegmentType::Wall),
|
|
||||||
(
|
|
||||||
FGVec2::lit("56.0", "-200.0"),
|
|
||||||
StagePolyLineSegmentType::Ceiling,
|
|
||||||
),
|
|
||||||
(FGVec2::lit("-56", "-200.0"), StagePolyLineSegmentType::Wall),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
commands.insert_resource(StageCollision {
|
|
||||||
stage_polys: vec![stage_poly.clone()],
|
|
||||||
});
|
|
||||||
commands.spawn((
|
|
||||||
Name::new("Stage Collision"),
|
|
||||||
stage_poly,
|
|
||||||
ChildOf(match_root),
|
|
||||||
));
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
shadow_maps_enabled: true,
|
shadow_maps_enabled: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user