diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..4699790b --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,38 @@ +[profile.dev] +split-debuginfo = "unpacked" +opt-level = 1 +debug = 1 +incremental = true + +# Optimize dependencies for faster builds +[profile.dev.package."*"] +opt-level = 3 +debug = false + +# Bevy-specific optimizations +[profile.dev.package.bevy] +opt-level = 3 +debug = false + +# Fast dev profile for quick iteration +[profile.dev-fast] +inherits = "dev" +opt-level = 0 +debug = false +incremental = true + +[target.x86_64-unknown-linux-gnu] +linker = "clang" +rustflags = ["-Clink-arg=-fuse-ld=lld", "-Ctarget-cpu=native"] + +[target.aarch64-unknown-linux-gnu] +linker = "clang" +rustflags = ["-Clink-arg=-fuse-ld=lld", "-Ctarget-cpu=native"] + +[target.x86_64-pc-windows-msvc] +linker = "rust-lld.exe" +rustflags = ["-Ctarget-feature=+crt-static"] + +# Build optimizations +[build] +jobs = 8 \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fcad9ff5..2b16cfe2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,74 +6,74 @@ on: pull_request: branches: [main] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always jobs: - # Run cargo test test: name: Test Suite runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 25 steps: + - name: Free disk space + run: sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/share/boost + - name: Checkout sources uses: actions/checkout@v4 - - name: Cache - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }} - - name: Install stable toolchain + + - name: Cache dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - - name: Install Dependencies - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - - name: Run cargo test - run: cargo test + + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev clang lld + + - name: Run tests + run: cargo test --workspace - # Run cargo clippy -- -D warnings - clippy_check: + clippy: name: Clippy runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 25 steps: + - name: Free disk space + run: sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /usr/local/share/boost + - name: Checkout sources uses: actions/checkout@v4 - - name: Cache - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.toml') }} - - name: Install stable toolchain + + - name: Cache dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: clippy - - name: Install Dependencies - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev + + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev clang lld + - name: Run clippy - run: cargo clippy -- -A clippy::upper-case-acronyms -A clippy::new-without-default -A clippy::manual-flatten -A clippy::excessive-precision -A clippy::too-many-arguments + run: cargo clippy --workspace -- -A clippy::upper-case-acronyms -A clippy::new-without-default -A clippy::manual-flatten -A clippy::excessive-precision -A clippy::too-many-arguments - # Run cargo fmt with check flag but allow failures format: name: Format runs-on: ubuntu-latest - timeout-minutes: 30 - continue-on-error: true + timeout-minutes: 10 steps: - name: Checkout sources uses: actions/checkout@v4 - - name: Install stable toolchain + + - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt - - name: Run cargo fmt - run: cargo fmt --all -- --check || true \ No newline at end of file + + - name: Check formatting + run: cargo fmt --all -- --check \ No newline at end of file diff --git a/.gitignore b/.gitignore index 879b0c58..bae87929 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,37 @@ -# Ignore build artifacts -/target +# Rust build artifacts +/target/ +**/target/ Cargo.lock -# Ignore save files +# IDE and editor settings +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Rust-specific +**/*.rs.bk +*.pdb + +# Temporary files +*.tmp +*.temp +*.log + +# Environment files +.env +.env.local +.env.*.local + +# Application save files save.json \ No newline at end of file diff --git a/crates/energy/README.md b/crates/energy/README.md new file mode 100644 index 00000000..33b47b03 --- /dev/null +++ b/crates/energy/README.md @@ -0,0 +1,3 @@ +# Energy + +Energy conservation, thermodynamics, electromagnetism, and wave mechanics for LP physics simulations. \ No newline at end of file diff --git a/crates/energy/src/conservation.rs b/crates/energy/src/conservation.rs index cfec34c4..47d2d424 100644 --- a/crates/energy/src/conservation.rs +++ b/crates/energy/src/conservation.rs @@ -26,10 +26,8 @@ pub struct EnergyQuantity { impl EnergyQuantity { /// Create a new energy quantity pub fn new(value: f32, energy_type: EnergyType, max_capacity: Option) -> Self { - let clamped_value = max_capacity - .map(|max| value.min(max)) - .unwrap_or(value); - + let clamped_value = max_capacity.map(|max| value.min(max)).unwrap_or(value); + Self { value: clamped_value.max(0.0), energy_type, @@ -55,8 +53,8 @@ impl EnergyQuantity { /// Energy transaction types for conservation accounting #[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)] pub enum TransactionType { - Input, // Energy entering the system - Output, // Energy leaving the system + Input, // Energy entering the system + Output, // Energy leaving the system } /// Event for energy transfers between entities @@ -118,13 +116,13 @@ impl EnergyAccountingLedger { TransactionType::Input => self.total_input += transaction.amount, TransactionType::Output => self.total_output += transaction.amount, } - + self.transactions.insert(0, transaction); if self.transactions.len() > self.max_history { self.transactions.pop(); } } - + /// Get the net energy change pub fn net_energy_change(&self) -> f32 { self.total_input - self.total_output @@ -150,20 +148,13 @@ impl Default for EnergyConservationTracker { } /// Utility function to verify energy conservation -pub fn verify_conservation( - initial_energy: f32, - final_energy: f32, - tolerance: f32, -) -> bool { +pub fn verify_conservation(initial_energy: f32, final_energy: f32, tolerance: f32) -> bool { // First law: Energy cannot be created or destroyed (final_energy - initial_energy).abs() <= tolerance } /// Utility function to calculate conversion efficiency -pub fn conversion_efficiency( - energy_input: f32, - energy_output: f32, -) -> f32 { +pub fn conversion_efficiency(energy_input: f32, energy_output: f32) -> f32 { if energy_input > 0.0 { (energy_output / energy_input).clamp(0.0, 1.0) } else { @@ -183,11 +174,9 @@ impl Plugin for EnergyConservationPlugin { .register_type::() .register_type::() .register_type::() - // Add resources .init_resource::() - // Add event channel .add_event::(); } -} \ No newline at end of file +} diff --git a/crates/energy/src/electromagnetism/fields.rs b/crates/energy/src/electromagnetism/fields.rs index 6a2f0f60..3d72cebb 100644 --- a/crates/energy/src/electromagnetism/fields.rs +++ b/crates/energy/src/electromagnetism/fields.rs @@ -124,10 +124,12 @@ pub fn calculate_field_interactions( // Electric field interactions for (source_entity, source_field) in electric_fields.iter() { for (target_entity, target_field) in electric_fields.iter() { - if source_entity == target_entity { continue; } - + if source_entity == target_entity { + continue; + } + let interaction_strength = source_field.strength() * target_field.strength(); - + if interaction_strength > f32::EPSILON { field_interaction_events.write(ElectromagneticFieldInteractionEvent { source: source_entity, @@ -141,10 +143,12 @@ pub fn calculate_field_interactions( // Magnetic field interactions (similar logic) for (source_entity, source_field) in magnetic_fields.iter() { for (target_entity, target_field) in magnetic_fields.iter() { - if source_entity == target_entity { continue; } - + if source_entity == target_entity { + continue; + } + let interaction_strength = source_field.strength() * target_field.strength(); - + if interaction_strength > f32::EPSILON { field_interaction_events.write(ElectromagneticFieldInteractionEvent { source: source_entity, @@ -165,11 +169,9 @@ impl Plugin for ElectromagneticFieldPlugin { // Register types for reflection .register_type::() .register_type::() - // Add electromagnetic field interaction event .add_event::() - // Add system for field interactions .add_systems(Update, calculate_field_interactions); } -} \ No newline at end of file +} diff --git a/crates/energy/src/electromagnetism/interactions.rs b/crates/energy/src/electromagnetism/interactions.rs index e6e6449b..f73a23a6 100644 --- a/crates/energy/src/electromagnetism/interactions.rs +++ b/crates/energy/src/electromagnetism/interactions.rs @@ -6,7 +6,7 @@ use bevy::prelude::*; const C: f32 = 299_792_458.0; /// Represents an electromagnetic wave component -#[derive(Debug, Component)] +#[derive(Debug, Component, Reflect)] pub struct ElectromagneticWave { /// Wave frequency in Hertz pub frequency: f32, @@ -74,7 +74,7 @@ impl ElectromagneticWave { } /// Material electromagnetic properties component -#[derive(Debug, Clone, Copy, Component)] +#[derive(Debug, Clone, Copy, Component, Reflect)] pub struct MaterialProperties { /// Electric permittivity pub permittivity: f32, @@ -118,4 +118,4 @@ impl MaterialProperties { // v = c/n C / self.refractive_index() } -} \ No newline at end of file +} diff --git a/crates/energy/src/electromagnetism/mod.rs b/crates/energy/src/electromagnetism/mod.rs index 5a198d98..c9f04da7 100644 --- a/crates/energy/src/electromagnetism/mod.rs +++ b/crates/energy/src/electromagnetism/mod.rs @@ -1,12 +1,25 @@ pub mod fields; pub mod interactions; +use bevy::prelude::*; + +pub struct ElectromagnetismPlugin; + +impl Plugin for ElectromagnetismPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .add_event::() + .add_systems(Update, fields::calculate_field_interactions); + } +} + /// The electromagnetism prelude. /// /// This includes the most common types for electromagnetic systems. pub mod prelude { pub use crate::electromagnetism::fields::{ElectricField, MagneticField}; - pub use crate::electromagnetism::interactions::{ - ElectromagneticWave, MaterialProperties - }; -} \ No newline at end of file + pub use crate::electromagnetism::interactions::{ElectromagneticWave, MaterialProperties}; +} diff --git a/crates/energy/src/lib.rs b/crates/energy/src/lib.rs index 1d458866..6de90d4a 100644 --- a/crates/energy/src/lib.rs +++ b/crates/energy/src/lib.rs @@ -1,11 +1,15 @@ -use bevy::prelude::*; - pub mod conservation; -pub mod thermodynamics; pub mod electromagnetism; +pub mod thermodynamics; pub mod waves; -// Add these new energy system related definitions +use bevy::prelude::*; + +pub use conservation::EnergyConservationPlugin; +pub use electromagnetism::ElectromagnetismPlugin; +pub use thermodynamics::ThermodynamicsPlugin; +pub use waves::WavesPlugin; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)] pub enum EnergyType { Generic, @@ -28,33 +32,37 @@ pub enum EnergyTransferError { /// Core trait for all energy-based systems in the simulation /// This complements the existing EnergyQuantity component pub trait EnergySystem { - // Core energy tracking + // Core energy tracking fn total_energy(&self) -> f32; - + // Energy transfer with entropy consideration fn transfer_energy(&mut self, energy: f32) -> Result { // Default implementation could track basic conservation Ok(energy) } - + // Transformation efficiency fn transformation_efficiency(&self) -> f32 { 1.0 // Default full efficiency } - + // Entropy generation during energy transfer fn entropy_generation(&self, _energy_transfer: f32) -> f32 { 0.0 // Default no entropy generation } - + // Energy type for this system fn energy_type(&self) -> EnergyType { EnergyType::Generic } - + // Create an EnergyTransaction for the ledger (optional) - fn create_transaction(&self, amount: f32, source: Option, - destination: Option) -> conservation::EnergyTransaction { + fn create_transaction( + &self, + amount: f32, + source: Option, + destination: Option, + ) -> conservation::EnergyTransaction { conservation::EnergyTransaction { transaction_type: if amount > 0.0 { conservation::TransactionType::Input @@ -69,25 +77,30 @@ pub trait EnergySystem { } } -/// Root energy prelude that re-exports all important items +/// Main plugin for all energy-related systems +#[derive(Default)] +pub struct EnergyPlugin; + +impl Plugin for EnergyPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .add_plugins(EnergyConservationPlugin) + .add_plugins(ThermodynamicsPlugin) + .add_plugins(ElectromagnetismPlugin) + .add_plugins(WavesPlugin); + } +} + pub mod prelude { - // Add the new trait and types to the prelude - pub use super::{EnergySystem, EnergyTransferError, EnergyType}; - - // Re-export from conservation + pub use super::{EnergySystem, EnergyTransferError}; + pub use crate::conservation::{ - EnergyQuantity, - EnergyTransferEvent, - EnergyAccountingLedger, - TransactionType, - EnergyConservationTracker, - verify_conservation, - conversion_efficiency, - EnergyConservationPlugin + conversion_efficiency, verify_conservation, EnergyAccountingLedger, + EnergyConservationPlugin, EnergyConservationTracker, EnergyQuantity, EnergyTransaction, + EnergyTransferEvent, EnergyType, TransactionType, }; - - // Re-export from submodules + + pub use crate::electromagnetism::prelude::*; pub use crate::thermodynamics::prelude::*; pub use crate::waves::prelude::*; - pub use crate::electromagnetism::prelude::*; -} \ No newline at end of file +} diff --git a/crates/energy/src/thermodynamics/entropy.rs b/crates/energy/src/thermodynamics/entropy.rs index 1314e5ce..4d7c9eba 100644 --- a/crates/energy/src/thermodynamics/entropy.rs +++ b/crates/energy/src/thermodynamics/entropy.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; /// Entropy component for thermodynamic systems -#[derive(Component, Debug, Clone, Copy)] +#[derive(Component, Debug, Clone, Copy, Reflect)] pub struct Entropy { /// Entropy in J/K pub value: f32, @@ -16,7 +16,7 @@ impl Entropy { } /// Process reversibility characteristic -#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)] pub enum Reversibility { Reversible, Irreversible, @@ -34,14 +34,14 @@ pub fn entropy_change_heat_transfer(heat_transferred: f32, temperature: f32) -> /// Calculate entropy change for irreversible processes pub fn entropy_change_irreversible( - energy_transferred: f32, // Energy transferred in process (J) - source_temperature: f32, // Temperature of source (K) - sink_temperature: f32, // Temperature of sink (K) + energy_transferred: f32, // Energy transferred in process (J) + source_temperature: f32, // Temperature of source (K) + sink_temperature: f32, // Temperature of sink (K) ) -> f32 { // For irreversible processes, total entropy change is positive // ΔS = Q/Tcold - Q/Thot if source_temperature > 0.0 && sink_temperature > 0.0 { - energy_transferred * (1.0/sink_temperature - 1.0/source_temperature) + energy_transferred * (1.0 / sink_temperature - 1.0 / source_temperature) } else { 0.0 } @@ -54,9 +54,6 @@ pub fn is_valid_process(total_entropy_change: f32) -> bool { } /// Calculate total entropy change of a system and its surroundings -pub fn total_entropy_change( - system_entropy_change: f32, - surroundings_entropy_change: f32, -) -> f32 { +pub fn total_entropy_change(system_entropy_change: f32, surroundings_entropy_change: f32) -> f32 { system_entropy_change + surroundings_entropy_change -} \ No newline at end of file +} diff --git a/crates/energy/src/thermodynamics/equilibrium.rs b/crates/energy/src/thermodynamics/equilibrium.rs index e0fd21a6..7e703ea5 100644 --- a/crates/energy/src/thermodynamics/equilibrium.rs +++ b/crates/energy/src/thermodynamics/equilibrium.rs @@ -1,13 +1,15 @@ use bevy::prelude::*; /// Component marking systems in thermal equilibrium -#[derive(Component, Debug)] +#[derive(Component, Debug, Reflect)] pub struct ThermalEquilibrium { pub connected_entities: Vec, } -/// Component for phase state of matter that will use the matter crate later once implemented -#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)] +/// Component for phase state of matter that will use the matter crate later once implemented, soon once PBMPM will be in place +/// and the matter crate is implemented +/// This is a placeholder for the actual phase state representation +#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)] pub enum PhaseState { Solid, Liquid, @@ -16,7 +18,7 @@ pub enum PhaseState { } /// Weighted equilibrium parameters -#[derive(Component, Debug, Clone, Copy)] +#[derive(Component, Debug, Clone, Copy)] pub struct ThermalProperties { pub thermal_mass: f32, } @@ -27,26 +29,26 @@ pub fn is_in_equilibrium( temp_b: f32, props_a: &ThermalProperties, props_b: &ThermalProperties, - tolerance: f32 + tolerance: f32, ) -> bool { // Weighted equilibrium considers both temperature and thermal properties - let weighted_diff = (temp_a - temp_b).abs() / - (1.0 + (props_a.thermal_mass * props_b.thermal_mass).sqrt()); - weighted_diff <= tolerance + let weighted_diff = + (temp_a - temp_b).abs() / (1.0 + (props_a.thermal_mass * props_b.thermal_mass).sqrt()); + weighted_diff <= tolerance } pub fn equilibrium_time_estimate( temp_diff: f32, // Initial temperature difference props_a: &ThermalProperties, props_b: &ThermalProperties, - heat_transfer_rate: f32, // Rate of heat transfer (W) + heat_transfer_rate: f32, // Rate of heat transfer (W) ) -> f32 { // More sophisticated estimate considering thermal masses let combined_thermal_mass = props_a.thermal_mass + props_b.thermal_mass; - if heat_transfer_rate > 0.0 { + if heat_transfer_rate > 0.0 { // Weighted by combined thermal mass combined_thermal_mass * temp_diff / heat_transfer_rate } else { f32::INFINITY } -} \ No newline at end of file +} diff --git a/crates/energy/src/thermodynamics/mod.rs b/crates/energy/src/thermodynamics/mod.rs index f23ebfe8..bfccdc50 100644 --- a/crates/energy/src/thermodynamics/mod.rs +++ b/crates/energy/src/thermodynamics/mod.rs @@ -2,8 +2,34 @@ pub mod entropy; pub mod equilibrium; pub mod thermal; +use bevy::prelude::*; + +pub struct ThermodynamicsPlugin; + +impl Plugin for ThermodynamicsPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .add_event::() + .add_systems(Update, thermal::calculate_thermal_transfer); + } +} + pub mod prelude { - pub use super::thermal::{Temperature, ThermalConductivity, ThermalDiffusivity, thermal_utils::heat_conduction}; - pub use super::entropy::{Entropy, Reversibility, entropy_change_heat_transfer, entropy_change_irreversible, is_valid_process, total_entropy_change}; - pub use super::equilibrium::{ThermalEquilibrium, PhaseState, ThermalProperties, is_in_equilibrium, equilibrium_time_estimate}; -} \ No newline at end of file + pub use super::entropy::{ + entropy_change_heat_transfer, entropy_change_irreversible, is_valid_process, + total_entropy_change, Entropy, Reversibility, + }; + pub use super::equilibrium::{ + equilibrium_time_estimate, is_in_equilibrium, PhaseState, ThermalEquilibrium, + ThermalProperties, + }; + pub use super::thermal::{ + thermal_utils::heat_conduction, Temperature, ThermalConductivity, ThermalDiffusivity, + }; +} diff --git a/crates/energy/src/thermodynamics/thermal.rs b/crates/energy/src/thermodynamics/thermal.rs index 6329bcc1..c28e8105 100644 --- a/crates/energy/src/thermodynamics/thermal.rs +++ b/crates/energy/src/thermodynamics/thermal.rs @@ -87,13 +87,16 @@ pub fn calculate_thermal_transfer( ) { // Use query.iter_combinations() to efficiently compare all entities let mut combinations = query.iter_combinations(); - while let Some([(entity1, temp1, conduct1), (entity2, temp2, conduct2)]) = combinations.fetch_next() { + while let Some([(entity1, temp1, conduct1), (entity2, temp2, conduct2)]) = + combinations.fetch_next() + { let temp_diff: f32 = temp1.value - temp2.value; let area: f32 = 1.0; // Placeholder let distance: f32 = 1.0; // Placeholder - - let heat_flow: f32 = (conduct1.value + conduct2.value) / 2.0 * area * temp_diff / distance.max(f32::EPSILON); - + + let heat_flow: f32 = + (conduct1.value + conduct2.value) / 2.0 * area * temp_diff / distance.max(f32::EPSILON); + if heat_flow.abs() > f32::EPSILON { thermal_transfer_events.write(ThermalTransferEvent { source: if heat_flow > 0.0 { entity1 } else { entity2 }, @@ -145,11 +148,9 @@ impl Plugin for ThermalSystemPlugin { .register_type::() .register_type::() .register_type::() - // Add thermal transfer event channel .add_event::() - // Add system for thermal calculations .add_systems(Update, calculate_thermal_transfer); } -} \ No newline at end of file +} diff --git a/crates/energy/src/waves/mod.rs b/crates/energy/src/waves/mod.rs index 80789792..c449b045 100644 --- a/crates/energy/src/waves/mod.rs +++ b/crates/energy/src/waves/mod.rs @@ -3,22 +3,41 @@ pub mod propagation; pub mod superposition; pub mod wave_equation; +use bevy::prelude::*; + +pub struct WavesPlugin; + +impl Plugin for WavesPlugin { + fn build(&self, app: &mut App) { + // Register wave components + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .add_event::() + .add_systems(Update, propagation::update_wave_displacements) + .add_systems(Update, superposition::update_standing_waves) + .add_systems(Update, wave_equation::update_wave_equation); + } +} + /// The waves prelude. /// /// This includes the most common types for wave systems. pub mod prelude { pub use crate::waves::oscillation::{ - WaveParameters, wave_number, angular_frequency, damping_from_half_life + angular_frequency, damping_from_half_life, wave_number, WaveParameters, }; pub use crate::waves::propagation::{ - WavePosition, WaveType, WaveCenterMarker, - solve_wave, solve_radial_wave, update_wave_displacements, create_linear_wave + create_linear_wave, solve_radial_wave, solve_wave, update_wave_displacements, + WaveCenterMarker, WavePosition, WaveType, }; pub use crate::waves::superposition::{ - StandingWaveMarker, solve_standing_wave, - update_standing_waves, create_standing_wave + create_standing_wave, solve_standing_wave, update_standing_waves, StandingWaveMarker, }; pub use crate::waves::wave_equation::{ - WaveEquation2D, WaveEquationComponent, update_wave_equation + update_wave_equation, WaveEquation2D, WaveEquationComponent, }; -} \ No newline at end of file +} diff --git a/crates/energy/src/waves/oscillation.rs b/crates/energy/src/waves/oscillation.rs index a71817c7..a23414e6 100644 --- a/crates/energy/src/waves/oscillation.rs +++ b/crates/energy/src/waves/oscillation.rs @@ -122,15 +122,22 @@ pub struct WaveGenerationEvent { } /// System for wave parameter validation -pub fn validate_wave_parameters( - mut wave_generation_events: EventReader, -) { +pub fn validate_wave_parameters(mut wave_generation_events: EventReader) { for event in wave_generation_events.read() { // Validate wave parameters - assert!(event.parameters.amplitude >= 0.0, "Wave amplitude must be non-negative"); - assert!(event.parameters.wavelength > 0.0, "Wavelength must be positive"); - assert!(event.parameters.speed >= 0.0, "Wave speed must be non-negative"); - + assert!( + event.parameters.amplitude >= 0.0, + "Wave amplitude must be non-negative" + ); + assert!( + event.parameters.wavelength > 0.0, + "Wavelength must be positive" + ); + assert!( + event.parameters.speed >= 0.0, + "Wave speed must be non-negative" + ); + // Optional: Log or handle invalid parameters } -} \ No newline at end of file +} diff --git a/crates/energy/src/waves/propagation.rs b/crates/energy/src/waves/propagation.rs index 48ebd9a9..b7e979be 100644 --- a/crates/energy/src/waves/propagation.rs +++ b/crates/energy/src/waves/propagation.rs @@ -1,5 +1,5 @@ +use super::oscillation::{angular_frequency, wave_number, WaveParameters}; use bevy::prelude::*; -use super::oscillation::{WaveParameters, wave_number, angular_frequency}; // Calculate modified angular frequency with dispersion #[inline] @@ -18,25 +18,25 @@ pub fn dispersive_angular_frequency(params: &WaveParameters, k: f32) -> f32 { } /// Component to store position for wave calculations -#[derive(Component, Debug, Clone)] +#[derive(Component, Debug, Clone, Reflect)] pub struct WavePosition(pub Vec2); impl WavePosition { pub fn new(position: Vec2) -> Self { Self(position) } - + pub fn from_xy(x: f32, y: f32) -> Self { Self(Vec2::new(x, y)) } - + pub fn from_x(x: f32) -> Self { Self(Vec2::new(x, 0.0)) } } /// Wave type marker component -#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)] pub enum WaveType { Traveling, Radial, @@ -44,26 +44,26 @@ pub enum WaveType { } // Marker component for wave centers (for radial waves) -#[derive(Component)] +#[derive(Component, Reflect)] pub struct WaveCenterMarker; #[inline] pub fn solve_wave(params: &WaveParameters, position: Vec2, time: f32) -> f32 { let k = wave_number(params.wavelength); let omega = dispersive_angular_frequency(params, k); - + let k_vec = params.direction.normalize() * k; let dot_product = k_vec.dot(position); - + // Calculate the phase argument for the wave function let phase = dot_product - omega * time + params.phase; - + // Apply damping over time let damping_factor = (-params.damping * time).exp(); - + // Use sine as the wave function (can be generalized later) let wave_function = phase.sin(); - + params.amplitude * damping_factor * wave_function } @@ -71,55 +71,63 @@ pub fn solve_wave(params: &WaveParameters, position: Vec2, time: f32) -> f32 { pub fn solve_radial_wave(params: &WaveParameters, center: Vec2, position: Vec2, time: f32) -> f32 { let k = wave_number(params.wavelength); let omega = dispersive_angular_frequency(params, k); - + // Calculate vector from center to position let displacement = position - center; let distance = displacement.length(); - + // Calculate spatial decay (amplitude decreases with distance) let spatial_falloff = if distance > 0.001 { 1.0 / distance.sqrt() } else { 1.0 }; - + // Calculate the phase argument, potentially allowing for direction-dependent effects let phase = k * distance - omega * time + params.phase; - + // Apply damping over time let damping_factor = (-params.damping * time).exp(); - + // Calculate the final wave displacement params.amplitude * spatial_falloff * damping_factor * phase.sin() } pub fn update_wave_displacements( time: Res