道岔仿真逻辑完善
多线程多app实验
This commit is contained in:
parent
3487b8eb1c
commit
072e6ba262
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"rtss",
|
||||
"timestep"
|
||||
]
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
||||
// 道岔设备状态组件
|
||||
|
14
src/main.rs
14
src/main.rs
@ -1,3 +1,15 @@
|
||||
use std::thread::{self, JoinHandle};
|
||||
|
||||
fn main() {
|
||||
rtss_simulation::Simulation::new().app.run();
|
||||
let mut list: Vec<JoinHandle<()>> = 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();
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Entity>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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::<Virtual>::from_max_delta(Duration::from_secs(5)))
|
||||
.insert_resource(Time::<Fixed>::from_duration(Duration::from_millis(1000)))
|
||||
.insert_resource(SimulationId::new(id.clone()))
|
||||
.insert_resource(EquipmentUidEntityMapping::default())
|
||||
.insert_resource(SimulationConfig::default())
|
||||
.add_event::<SimulationControlEvent>()
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
@ -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<SimulationControlEvent>,
|
||||
mut time: ResMut<Time<Virtual>>,
|
||||
sid: Res<crate::SimulationId>,
|
||||
mut exit: EventWriter<AppExit>,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<TurnoutControlEvent>,
|
||||
time: ResMut<Time<Fixed>>,
|
||||
config: Res<SimulationConfig>,
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user