diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a6253a9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cSpell.words": [ + "rtss", + "timestep" + ] +} diff --git a/src/components/equipment.rs b/src/components/equipment.rs index 3184153..ea66007 100644 --- a/src/components/equipment.rs +++ b/src/components/equipment.rs @@ -10,12 +10,12 @@ impl Default for Uid { } // 两常态位置转换组件,用于像道岔位置,屏蔽门位置等 -#[derive(Component, Debug, Clone, PartialEq, Eq, Default)] +#[derive(Component, Debug, Clone, PartialEq, Default)] pub struct TwoNormalPositionsConversion { // 当前实际位置,百分比值,0-100 pub position: i32, // 当前转换速度 - pub velocity: i32, + pub velocity: f32, } // 道岔设备状态组件 diff --git a/src/main.rs b/src/main.rs index 35efc25..8b2457b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,15 @@ +use std::thread::{self, JoinHandle}; + fn main() { - rtss_simulation::Simulation::new().app.run(); + let mut list: Vec> = Vec::new(); + for i in 0..100 { + let thread_handler = thread::spawn(move || { + let mut sim = rtss_simulation::Simulation::new(i.to_string()); + sim.run(); + }); + list.push(thread_handler); + } + for handler in list { + handler.join().unwrap(); + } } diff --git a/src/resources/mod.rs b/src/resources/mod.rs index 67c1d96..a207dcc 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, ops::Deref}; use bevy_ecs::{entity::Entity, system::Resource}; @@ -7,3 +7,37 @@ use bevy_ecs::{entity::Entity, system::Resource}; pub struct EquipmentUidEntityMapping { pub turnout_mapping: HashMap, } + +#[derive(Resource, Debug)] +pub struct SimulationId(String); + +impl SimulationId { + pub fn new(id: String) -> Self { + SimulationId(id) + } +} + +impl Deref for SimulationId { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Resource, Debug)] +pub struct SimulationConfig { + // 仿真倍速 + pub simulation_speed: f32, + // 道岔转换总时间,单位ms + pub turnout_transform_time: i32, +} + +impl Default for SimulationConfig { + fn default() -> Self { + SimulationConfig { + simulation_speed: 1.0, + turnout_transform_time: 3500, + } + } +} diff --git a/src/simulation.rs b/src/simulation.rs index eb43b1d..962a033 100644 --- a/src/simulation.rs +++ b/src/simulation.rs @@ -3,25 +3,20 @@ use std::time::Duration; use crate::{ control_simulation, handle_turnout_control, loading, simulation_status_control, turnout_state_update, two_normal_position_transform, EquipmentUidEntityMapping, - SimulationControlEvent, + SimulationConfig, SimulationControlEvent, SimulationId, }; use bevy_app::{prelude::*, ScheduleRunnerPlugin}; use bevy_ecs::schedule::IntoSystemConfigs; -use bevy_log::LogPlugin; +use bevy_log::{debug, LogPlugin}; use bevy_time::{prelude::*, TimePlugin}; pub struct Simulation { + id: String, pub app: App, } -impl Default for Simulation { - fn default() -> Self { - Self::new() - } -} - impl Simulation { - pub fn new() -> Self { + pub fn new(id: String) -> Self { let mut app = App::new(); app.add_plugins(ScheduleRunnerPlugin::run_loop(Duration::from_millis(1000))) .add_plugins(LogPlugin { @@ -31,7 +26,9 @@ impl Simulation { .add_plugins(TimePlugin) .insert_resource(Time::::from_max_delta(Duration::from_secs(5))) .insert_resource(Time::::from_duration(Duration::from_millis(1000))) + .insert_resource(SimulationId::new(id.clone())) .insert_resource(EquipmentUidEntityMapping::default()) + .insert_resource(SimulationConfig::default()) .add_event::() .add_systems(Startup, loading) .add_systems(Update, control_simulation) @@ -41,6 +38,19 @@ impl Simulation { ) .observe(handle_turnout_control) .observe(simulation_status_control); - Simulation { app } + Simulation { id, app } + } + + pub fn id(&self) -> &str { + &self.id + } + + pub fn run(&mut self) { + self.app.run(); + } + + pub fn close(&mut self) { + debug!("close simulation id={}", self.id); + self.app.world_mut().trigger(SimulationControlEvent::Exit); } } diff --git a/src/systems/control.rs b/src/systems/control.rs index 8d13b74..b23100e 100644 --- a/src/systems/control.rs +++ b/src/systems/control.rs @@ -21,18 +21,16 @@ pub fn control_simulation( // debug!("Uid: {:?}, Entity: {:?}", uid, entity); commands.trigger_targets(TurnoutControlEvent::FC, *entity); }); - if time.elapsed_seconds() > 13.0 { + if time.elapsed_seconds() > 7.0 { debug!("send exit event"); commands.trigger(SimulationControlEvent::Exit); } - // if time.elapsed_seconds() > 10.0 { - // commands.trigger(SimulationControlEvent::Pause); - // } } pub fn simulation_status_control( trigger: Trigger, mut time: ResMut>, + sid: Res, mut exit: EventWriter, ) { match trigger.event() { @@ -45,7 +43,7 @@ pub fn simulation_status_control( time.unpause(); } SimulationControlEvent::Exit => { - debug!("Exiting simulation"); + debug!("Exiting simulation, id={:?}", *sid); exit.send(AppExit::Success); } } diff --git a/src/systems/turnout.rs b/src/systems/turnout.rs index 2919b3f..a5c2738 100644 --- a/src/systems/turnout.rs +++ b/src/systems/turnout.rs @@ -1,33 +1,41 @@ use bevy_ecs::{ entity::Entity, observer::Trigger, - system::{Query, ResMut}, + system::{Query, Res, ResMut}, }; use bevy_log::debug; use bevy_time::{Fixed, Time}; -use crate::{events::TurnoutControlEvent, TurnoutState, TwoNormalPositionsConversion, Uid}; +use crate::{ + events::TurnoutControlEvent, SimulationConfig, TurnoutState, TwoNormalPositionsConversion, Uid, +}; // 道岔控制事件处理系统 pub fn handle_turnout_control( trigger: Trigger, time: ResMut>, + config: Res, mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsConversion)>, ) { let (uid, mut state, mut conversion) = query .get_mut(trigger.entity()) .expect("通过entity获取道岔异常"); + let v = calculate_avg_velocity( + TWO_NORMAL_POSITION_MAX as f32, + config.turnout_transform_time as f32, + time.timestep().as_millis() as f32, + ); match trigger.event() { TurnoutControlEvent::DC => { state.dc = true; state.fc = false; - conversion.velocity = -3000 / time.timestep().as_millis() as i32; + conversion.velocity = -v; debug!("道岔定操处理:{:?}", uid); } TurnoutControlEvent::FC => { state.dc = false; state.fc = true; - conversion.velocity = 3000 / time.timestep().as_millis() as i32; + conversion.velocity = v; debug!("道岔反操处理:uid={:?}, conversion={:?}", uid, conversion); } } @@ -42,19 +50,26 @@ pub fn turnout_state_update( "更新道岔状态:Uid={:?}, State={:?}, Conversion={:?}", uid, state, conversion ); - if conversion.velocity != 0 { - state.db = false; - state.fb = false; - } else if conversion.position == 0 { + if conversion.position == 0 { state.db = true; state.fb = false; } else if conversion.position == 100 { state.db = false; state.fb = true; + } else { + state.db = false; + state.fb = false; } } } +// 计算平均速度 +fn calculate_avg_velocity(total_distance: f32, total_time: f32, time_step: f32) -> f32 { + total_distance / (total_time / time_step) +} + +const TWO_NORMAL_POSITION_MIN: i32 = 0; +const TWO_NORMAL_POSITION_MAX: i32 = 100; // 两常态位置转换系统 pub fn two_normal_position_transform( mut query: Query<(Entity, &Uid, &mut TwoNormalPositionsConversion)>, @@ -64,16 +79,16 @@ pub fn two_normal_position_transform( "Entity: {:?}, Uid: {:?}, Conversion: {:?}", entity, uid, conversion ); - if conversion.velocity == 0 { + if conversion.velocity == 0f32 { continue; } - let p = conversion.position + conversion.velocity; - if p > 100 { - conversion.position = 100; - conversion.velocity = 0; - } else if p < 0 { - conversion.position = 0; - conversion.velocity = 0; + let p = conversion.position + conversion.velocity as i32; + if p > TWO_NORMAL_POSITION_MAX { + conversion.position = TWO_NORMAL_POSITION_MAX; + conversion.velocity = TWO_NORMAL_POSITION_MIN as f32; + } else if p < TWO_NORMAL_POSITION_MIN { + conversion.position = TWO_NORMAL_POSITION_MIN; + conversion.velocity = 0 as f32; } else { conversion.position = p; }