diff --git a/src/main.rs b/src/main.rs index 16fffd7..cc77096 100755 --- a/src/main.rs +++ b/src/main.rs @@ -305,7 +305,11 @@ fn toggle_editor(game: &mut Game) fn handle_editor_pick(game: &mut Game, x: f32, y: f32) { - let view = match camera_view_matrix(&game.world) + let view = match camera_view_matrix( + &game.world.cameras, + &game.world.transforms, + &game.world.follows, + ) { Some(v) => v, None => return, @@ -340,7 +344,11 @@ fn submit_frame( Some(t) => t, None => return, }; - let view = match camera_view_matrix(&game.world) + let view = match camera_view_matrix( + &game.world.cameras, + &game.world.transforms, + &game.world.follows, + ) { Some(v) => v, None => return, @@ -350,8 +358,13 @@ fn submit_frame( let view_proj = projection * view; let player_pos = game.world.player_position(); - let (billboard_calls, text_vertices) = - dialog_bubble_render_system(&game.world, camera_transform.position, view_proj); + let (billboard_calls, text_vertices) = dialog_bubble_render_system( + &game.world.transforms, + &game.world.dialog_bubbles, + &game.world.bubble_tags, + camera_transform.position, + view_proj, + ); let frame = render::render( &view, @@ -414,17 +427,67 @@ fn main() -> Result<(), Box> } // --- intent generation --- - camera_input_system(&mut game.world, &game.input_state); - player_input_system(&mut game.world, &game.input_state); - dialog_camera_transition_system(&mut game.world, game.camera_entity); + camera_input_system( + &mut game.world.cameras, + &game.world.follows, + &game.input_state, + ); + player_input_system( + &game.world.cameras, + &game.world.follows, + &game.world.player_tags, + &mut game.world.inputs, + &game.input_state, + ); + dialog_camera_transition_system( + &game.world.bubble_tags, + &mut game.world.camera_transition_intents, + &mut game.world.was_dialog_active, + game.camera_entity, + ); // --- intent processing + camera --- - camera_intent_system(&mut game.world); - camera_noclip_system(&mut game.world, &game.input_state, delta); - dialog_camera_system(&mut game.world, delta); - camera_follow_system(&mut game.world); - camera_transition_system(&mut game.world, delta); - camera_ground_clamp_system(&mut game.world); + camera_intent_system( + &mut game.world.follow_player_intents, + &mut game.world.stop_following_intents, + &mut game.world.camera_transition_intents, + &mut game.world.follows, + &mut game.world.transforms, + &mut game.world.cameras, + &game.world.player_tags, + &mut game.world.camera_transitions, + ); + camera_noclip_system( + &game.world.cameras, + &game.world.follows, + &mut game.world.transforms, + &game.input_state, + delta, + ); + let player_pos = game.world.player_position(); + dialog_camera_system( + &mut game.world.cameras, + &mut game.world.transforms, + &game.world.bubble_tags, + player_pos, + delta, + ); + camera_follow_system( + &mut game.world.follows, + &game.world.cameras, + &mut game.world.transforms, + ); + camera_transition_system( + &mut game.world.camera_transitions, + &mut game.world.transforms, + &mut game.world.cameras, + delta, + ); + camera_ground_clamp_system( + &game.world.cameras, + &game.world.follows, + &mut game.world.transforms, + ); // --- editor overlay --- if game.editor.active @@ -444,10 +507,42 @@ fn main() -> Result<(), Box> { state_machine_physics_system(&mut game.world, FIXED_TIMESTEP); PhysicsManager::physics_step(); - physics_sync_system(&mut game.world); - trigger_system(&mut game.world); - dialog_system(&mut game.world, FIXED_TIMESTEP); - dialog_projectile_system(&mut game.world, &game.input_state); + physics_sync_system( + &game.world.entities, + &game.world.physics, + &mut game.world.transforms, + ); + trigger_system( + &mut game.world.trigger_events, + &mut game.world.triggers, + &game.world.transforms, + &game.world.player_tags, + ); + dialog_system( + &mut game.world.entities, + &game.world.trigger_events, + &game.world.dialog_sources, + &mut game.world.bubble_tags, + &mut game.world.dialog_bubbles, + &mut game.world.transforms, + &mut game.world.names, + &game.world.player_tags, + &mut game.world.projectile_tags, + &mut game.world.dialog_projectiles, + &mut game.world.dialog_outcomes, + FIXED_TIMESTEP, + ); + dialog_projectile_system( + &game.world.player_tags, + &mut game.world.transforms, + &mut game.world.projectile_tags, + &mut game.world.dialog_projectiles, + &mut game.world.spawn_particle_intents, + &mut game.world.dialog_outcomes, + &game.world.leaping_states, + &game.world.rolling_states, + &game.input_state, + ); game.physics_accumulator -= FIXED_TIMESTEP; } @@ -455,19 +550,33 @@ fn main() -> Result<(), Box> // --- per-frame systems --- state_machine_system(&mut game.world, delta); - rotate_system(&mut game.world, delta); + rotate_system(&game.world.rotates, &mut game.world.transforms, delta); - tree_occlusion_system(&mut game.world); - tree_dissolve_update_system(&mut game.world, delta); - tree_instance_buffer_update_system(&mut game.world); + tree_occlusion_system( + &game.world.player_tags, + &game.world.transforms, + &game.world.cameras, + &mut game.world.tree_instances, + ); + tree_dissolve_update_system(&mut game.world.tree_instances, delta); + tree_instance_buffer_update_system(&game.world.tree_instances); - let spotlights = spotlight_sync_system(&game.world); + let spotlights = spotlight_sync_system(&game.world.spotlights, &game.world.transforms); render::update_spotlights(spotlights); - snow_system(&mut game.world); + snow_system( + &game.world.cameras, + &game.world.transforms, + &game.world.player_tags, + &game.world.follows, + &mut game.world.snow_layer, + ); - particle_intent_system(&mut game.world); - particle_update_system(&mut game.world, delta); + particle_intent_system( + &mut game.world.particle_buffers, + &mut game.world.spawn_particle_intents, + ); + particle_update_system(&mut game.world.particle_buffers, delta); let particle_cam_pos = game.world.active_camera_position(); if let Some(ref mut buffers) = game.world.particle_buffers { @@ -475,7 +584,12 @@ fn main() -> Result<(), Box> } // --- draw call collection --- - let mut draw_calls = render_system(&game.world); + let mut draw_calls = render_system( + &game.world.entities, + &game.world.transforms, + &game.world.meshes, + &game.world.dissolves, + ); if let Some(ref snow_layer) = game.world.snow_layer { draw_calls.extend(snow_layer.get_draw_calls()); diff --git a/src/systems/camera.rs b/src/systems/camera.rs index 6b45837..2394e31 100644 --- a/src/systems/camera.rs +++ b/src/systems/camera.rs @@ -1,22 +1,32 @@ use glam::Vec3; -use crate::components::camera::CameraTransition; +use crate::components::camera::{CameraComponent, CameraTransition}; +use crate::components::intent::{CameraTransitionIntent, FollowPlayerIntent, StopFollowingIntent}; use crate::components::FollowComponent; use crate::entity::EntityHandle; use crate::physics::PhysicsManager; use crate::utility::input::InputState; -use crate::world::{Transform, World}; +use crate::utility::transform::Transform; +use crate::world::Storage; const CAMERA_GROUND_OFFSET: f32 = 2.0; -pub fn camera_view_matrix(world: &World) -> Option +pub fn camera_view_matrix( + cameras: &Storage, + transforms: &Storage, + follows: &Storage, +) -> Option { - let (camera_entity, camera_component) = world.active_camera()?; - let camera_transform = world.transforms.get(camera_entity)?; + let (camera_entity, camera_component) = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, c)| (*e, c))?; + let camera_transform = transforms.get(camera_entity)?; - if let Some(follow) = world.follows.get(camera_entity) + if let Some(follow) = follows.get(camera_entity) { - if let Some(target_transform) = world.transforms.get(follow.target) + if let Some(target_transform) = transforms.get(follow.target) { return Some(glam::Mat4::look_at_rh( camera_transform.position, @@ -35,13 +45,17 @@ pub fn camera_view_matrix(world: &World) -> Option )) } -pub fn camera_input_system(world: &mut World, input_state: &InputState) +pub fn camera_input_system( + cameras: &mut Storage, + follows: &Storage, + input_state: &InputState, +) { - let cameras: Vec<_> = world.cameras.all(); + let camera_entities: Vec<_> = cameras.all(); - for camera_entity in cameras + for camera_entity in camera_entities { - if let Some(camera) = world.cameras.get_mut(camera_entity) + if let Some(camera) = cameras.get_mut(camera_entity) { if !camera.is_active { @@ -50,7 +64,7 @@ pub fn camera_input_system(world: &mut World, input_state: &InputState) if input_state.mouse_delta.0.abs() > 0.0 || input_state.mouse_delta.1.abs() > 0.0 { - let is_following = world.follows.get(camera_entity).is_some(); + let is_following = follows.get(camera_entity).is_some(); camera.yaw += input_state.mouse_delta.0 * 0.0008; @@ -71,49 +85,61 @@ pub fn camera_input_system(world: &mut World, input_state: &InputState) } } -pub fn camera_intent_system(world: &mut World) +pub fn camera_intent_system( + follow_player_intents: &mut Storage, + stop_following_intents: &mut Storage, + camera_transition_intents: &mut Storage, + follows: &mut Storage, + transforms: &mut Storage, + cameras: &mut Storage, + player_tags: &Storage<()>, + camera_transitions: &mut Storage, +) { - let follow_entities: Vec = world.follow_player_intents.all(); + let follow_entities: Vec = follow_player_intents.all(); for entity in follow_entities { - start_camera_following(world, entity); - world.follow_player_intents.remove(entity); + start_camera_following(follows, transforms, cameras, player_tags, entity); + follow_player_intents.remove(entity); } - let stop_entities: Vec = world.stop_following_intents.all(); + let stop_entities: Vec = stop_following_intents.all(); for entity in stop_entities { - stop_camera_following(world, entity); - world.stop_following_intents.remove(entity); + stop_camera_following(follows, transforms, cameras, entity); + stop_following_intents.remove(entity); } - let transition_entities: Vec = world.camera_transition_intents.all(); + let transition_entities: Vec = camera_transition_intents.all(); for entity in transition_entities { - let duration = world - .camera_transition_intents + let duration = camera_transition_intents .get(entity) .map(|i| i.duration) .unwrap_or(0.5); - start_camera_transition(world, entity, duration); - world.camera_transition_intents.remove(entity); + start_camera_transition(camera_transitions, transforms, cameras, entity, duration); + camera_transition_intents.remove(entity); } } -pub fn camera_follow_system(world: &mut World) +pub fn camera_follow_system( + follows: &mut Storage, + cameras: &Storage, + transforms: &mut Storage, +) { - let camera_entities: Vec<_> = world.follows.all(); + let camera_entities: Vec<_> = follows.all(); for camera_entity in camera_entities { - if let Some(camera) = world.cameras.get(camera_entity) + if let Some(camera) = cameras.get(camera_entity) { - if let Some(follow) = world.follows.get(camera_entity) + if let Some(follow) = follows.get(camera_entity) { let target_entity = follow.target; let offset = follow.offset.position; - if let Some(target_transform) = world.transforms.get(target_entity) + if let Some(target_transform) = transforms.get(target_entity) { let target_position = target_transform.position; let distance = offset.length(); @@ -126,13 +152,11 @@ pub fn camera_follow_system(world: &mut World) let new_offset = Vec3::new(offset_x, offset_y, offset_z); - world - .transforms - .with_mut(camera_entity, |camera_transform| { - camera_transform.position = target_position + new_offset; - }); + transforms.with_mut(camera_entity, |camera_transform| { + camera_transform.position = target_position + new_offset; + }); - world.follows.components.get_mut(&camera_entity).map(|f| { + follows.components.get_mut(&camera_entity).map(|f| { f.offset.position = new_offset; }); } @@ -141,23 +165,29 @@ pub fn camera_follow_system(world: &mut World) } } -pub fn camera_noclip_system(world: &mut World, input_state: &InputState, delta: f32) +pub fn camera_noclip_system( + cameras: &Storage, + follows: &Storage, + transforms: &mut Storage, + input_state: &InputState, + delta: f32, +) { if !input_state.mouse_captured { return; } - let cameras: Vec<_> = world.cameras.all(); + let camera_entities: Vec<_> = cameras.all(); - for camera_entity in cameras + for camera_entity in camera_entities { - if world.follows.get(camera_entity).is_some() + if follows.get(camera_entity).is_some() { continue; } - if let Some(camera) = world.cameras.get(camera_entity) + if let Some(camera) = cameras.get(camera_entity) { if !camera.is_active { @@ -201,7 +231,7 @@ pub fn camera_noclip_system(world: &mut World, input_state: &InputState, delta: speed *= 10.0; } - if let Some(camera_transform) = world.transforms.get_mut(camera_entity) + if let Some(camera_transform) = transforms.get_mut(camera_entity) { camera_transform.position += forward * input_vec.z * speed; camera_transform.position += right * input_vec.x * speed; @@ -211,28 +241,34 @@ pub fn camera_noclip_system(world: &mut World, input_state: &InputState, delta: } } -fn start_camera_following(world: &mut World, camera_entity: crate::entity::EntityHandle) +fn start_camera_following( + follows: &mut Storage, + transforms: &mut Storage, + cameras: &mut Storage, + player_tags: &Storage<()>, + camera_entity: EntityHandle, +) { - if let Some(camera_transform) = world.transforms.get(camera_entity) + if let Some(camera_transform) = transforms.get(camera_entity) { - let player_entities = world.player_tags.all(); + let player_entities = player_tags.all(); if let Some(&player_entity) = player_entities.first() { - if let Some(target_transform) = world.transforms.get(player_entity) + if let Some(target_transform) = transforms.get(player_entity) { let offset = camera_transform.position - target_transform.position; let distance = offset.length(); if distance > 0.0 { - if let Some(camera) = world.cameras.get_mut(camera_entity) + if let Some(camera) = cameras.get_mut(camera_entity) { camera.pitch = (offset.y / distance).asin(); camera.yaw = offset.z.atan2(offset.x) + std::f32::consts::PI; } } - world.follows.insert( + follows.insert( camera_entity, FollowComponent { target: player_entity, @@ -246,20 +282,25 @@ fn start_camera_following(world: &mut World, camera_entity: crate::entity::Entit } } -fn stop_camera_following(world: &mut World, camera_entity: crate::entity::EntityHandle) +fn stop_camera_following( + follows: &mut Storage, + transforms: &Storage, + cameras: &mut Storage, + camera_entity: EntityHandle, +) { - if let Some(follow) = world.follows.get(camera_entity) + if let Some(follow) = follows.get(camera_entity) { let target_entity = follow.target; - if let Some(camera_transform) = world.transforms.get(camera_entity) + if let Some(camera_transform) = transforms.get(camera_entity) { - if let Some(target_transform) = world.transforms.get(target_entity) + if let Some(target_transform) = transforms.get(target_entity) { let look_direction = (target_transform.position - camera_transform.position).normalize(); - if let Some(camera) = world.cameras.get_mut(camera_entity) + if let Some(camera) = cameras.get_mut(camera_entity) { camera.yaw = look_direction.z.atan2(look_direction.x); camera.pitch = look_direction.y.asin(); @@ -267,24 +308,34 @@ fn stop_camera_following(world: &mut World, camera_entity: crate::entity::Entity } } - world.follows.remove(camera_entity); + follows.remove(camera_entity); } } -pub fn camera_ground_clamp_system(world: &mut World) +pub fn camera_ground_clamp_system( + cameras: &Storage, + follows: &Storage, + transforms: &mut Storage, +) { - let Some((camera_entity, _)) = world.active_camera() + let camera_entity = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, _)| *e); + + let Some(camera_entity) = camera_entity else { return; }; - if world.follows.get(camera_entity).is_none() + if follows.get(camera_entity).is_none() { return; } - world.transforms.with_mut(camera_entity, |t| { + transforms.with_mut(camera_entity, |t| { let ground_y = PhysicsManager::get_terrain_height_at(t.position.x, t.position.z).unwrap_or(0.0); let min_y = ground_y + CAMERA_GROUND_OFFSET; @@ -295,9 +346,15 @@ pub fn camera_ground_clamp_system(world: &mut World) }); } -fn start_camera_transition(world: &mut World, camera_entity: EntityHandle, duration: f32) +fn start_camera_transition( + camera_transitions: &mut Storage, + transforms: &mut Storage, + cameras: &mut Storage, + camera_entity: EntityHandle, + duration: f32, +) { - let Some(camera) = world.cameras.get(camera_entity) + let Some(camera) = cameras.get(camera_entity) else { return; @@ -306,12 +363,11 @@ fn start_camera_transition(world: &mut World, camera_entity: EntityHandle, durat let source_yaw = camera.yaw; let source_pitch = camera.pitch; - let source_position = world - .transforms + let source_position = transforms .with(camera_entity, |t| t.position) .unwrap_or(Vec3::ZERO); - world.camera_transitions.insert( + camera_transitions.insert( camera_entity, CameraTransition { source_position, @@ -323,14 +379,19 @@ fn start_camera_transition(world: &mut World, camera_entity: EntityHandle, durat ); } -pub fn camera_transition_system(world: &mut World, delta: f32) +pub fn camera_transition_system( + camera_transitions: &mut Storage, + transforms: &mut Storage, + cameras: &mut Storage, + delta: f32, +) { - let entities: Vec = world.camera_transitions.all(); + let entities: Vec = camera_transitions.all(); for entity in entities { let finished = { - let Some(transition) = world.camera_transitions.get_mut(entity) + let Some(transition) = camera_transitions.get_mut(entity) else { continue; @@ -345,11 +406,11 @@ pub fn camera_transition_system(world: &mut World, delta: f32) let source_pitch = transition.source_pitch; let finished = t >= 1.0; - world.transforms.with_mut(entity, |transform| { + transforms.with_mut(entity, |transform| { transform.position = source_position.lerp(transform.position, t); }); - if let Some(camera) = world.cameras.get_mut(entity) + if let Some(camera) = cameras.get_mut(entity) { camera.yaw = lerp_angle(source_yaw, camera.yaw, t); camera.pitch = source_pitch + (camera.pitch - source_pitch) * t; @@ -357,13 +418,12 @@ pub fn camera_transition_system(world: &mut World, delta: f32) if !finished { - if let Some(transition) = world.camera_transitions.get_mut(entity) + if let Some(transition) = camera_transitions.get_mut(entity) { - let pos = world - .transforms + let pos = transforms .with(entity, |tr| tr.position) .unwrap_or(Vec3::ZERO); - let cam = world.cameras.get(entity); + let cam = cameras.get(entity); transition.source_position = pos; if let Some(cam) = cam { @@ -378,7 +438,7 @@ pub fn camera_transition_system(world: &mut World, delta: f32) if finished { - world.camera_transitions.remove(entity); + camera_transitions.remove(entity); } } } diff --git a/src/systems/dialog_camera.rs b/src/systems/dialog_camera.rs index c0f13ea..de436cc 100644 --- a/src/systems/dialog_camera.rs +++ b/src/systems/dialog_camera.rs @@ -1,18 +1,23 @@ use glam::Vec3; +use crate::components::camera::CameraComponent; use crate::components::intent::CameraTransitionIntent; use crate::entity::EntityHandle; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn dialog_camera_transition_system(world: &mut World, camera_entity: EntityHandle) +pub fn dialog_camera_transition_system( + bubble_tags: &Storage<()>, + camera_transition_intents: &mut Storage, + was_dialog_active: &mut bool, + camera_entity: EntityHandle, +) { - let dialog_active = !world.bubble_tags.all().is_empty(); - if dialog_active != world.was_dialog_active + let dialog_active = !bubble_tags.all().is_empty(); + if dialog_active != *was_dialog_active { - world - .camera_transition_intents - .insert(camera_entity, CameraTransitionIntent { duration: 0.8 }); - world.was_dialog_active = dialog_active; + camera_transition_intents.insert(camera_entity, CameraTransitionIntent { duration: 0.8 }); + *was_dialog_active = dialog_active; } } @@ -21,21 +26,30 @@ const VERTICAL_BIAS: f32 = 0.4; const MIN_DISTANCE: f32 = 8.0; const MAX_DISTANCE: f32 = 24.0; -pub fn dialog_camera_system(world: &mut World, delta: f32) +pub fn dialog_camera_system( + cameras: &mut Storage, + transforms: &mut Storage, + bubble_tags: &Storage<()>, + player_pos: Vec3, + delta: f32, +) { - let Some((camera_entity, _)) = world.active_camera() + let camera_entity = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, _)| *e); + + let Some(camera_entity) = camera_entity else { return; }; - let player_pos = world.player_position(); - - let bubble_positions: Vec = world - .bubble_tags + let bubble_positions: Vec = bubble_tags .all() .iter() - .filter_map(|&bubble| world.transforms.with(bubble, |t| t.position)) + .filter_map(|&bubble| transforms.with(bubble, |t| t.position)) .collect(); if bubble_positions.is_empty() @@ -63,20 +77,19 @@ pub fn dialog_camera_system(world: &mut World, delta: f32) let target_camera_pos = centroid + camera_back_dir * camera_distance + Vec3::Y * camera_distance * VERTICAL_BIAS; - let current_camera_pos = world - .transforms + let current_camera_pos = transforms .with(camera_entity, |t| t.position) .unwrap_or(target_camera_pos); let smoothed = current_camera_pos.lerp(target_camera_pos, (CAMERA_LAG * delta).min(1.0)); - world.transforms.with_mut(camera_entity, |t| { + transforms.with_mut(camera_entity, |t| { t.position = smoothed; }); let look_target = centroid; - if let Some(camera) = world.cameras.get_mut(camera_entity) + if let Some(camera) = cameras.get_mut(camera_entity) { let look_dir = (look_target - smoothed).normalize_or(-Vec3::Z); camera.yaw = look_dir.z.atan2(look_dir.x); diff --git a/src/systems/dialog_projectile.rs b/src/systems/dialog_projectile.rs index a57c10a..5902367 100644 --- a/src/systems/dialog_projectile.rs +++ b/src/systems/dialog_projectile.rs @@ -2,39 +2,53 @@ use std::f32::consts::PI; use glam::Vec3; -use crate::components::dialog::{DialogOutcome, DialogOutcomeEvent, ParryButton}; +use crate::components::dialog::{ + DialogOutcome, DialogOutcomeEvent, DialogProjectileComponent, ParryButton, +}; use crate::components::particle::{ParticleEmitterConfig, SpawnParticleIntent}; +use crate::components::player_states::{LeapingState, RollingState}; use crate::entity::EntityHandle; use crate::utility::input::InputState; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; const PROJECTILE_SPEED: f32 = 6.0; const PARRY_WINDOW_RADIUS: f32 = 3.5; const HIT_RADIUS: f32 = 1.2; -pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) +pub fn dialog_projectile_system( + player_tags: &Storage<()>, + transforms: &mut Storage, + projectile_tags: &mut Storage<()>, + dialog_projectiles: &mut Storage, + spawn_particle_intents: &mut Vec, + dialog_outcomes: &mut Vec, + leaping_states: &Storage, + rolling_states: &Storage, + input_state: &InputState, +) { - let player_entity = world.player_tags.all().into_iter().next(); + let player_entity = player_tags.all().into_iter().next(); let Some(player_entity) = player_entity else { return; }; - let player_pos = world - .transforms + let player_pos = transforms .with(player_entity, |t| t.position) .unwrap_or(Vec3::ZERO); - let player_is_evading = is_player_evading(world, player_entity); + let player_is_evading = + leaping_states.get(player_entity).is_some() || rolling_states.get(player_entity).is_some(); - let projectiles: Vec = world.projectile_tags.all(); + let projectiles: Vec = projectile_tags.all(); let mut outcomes: Vec = Vec::new(); let mut to_despawn: Vec = Vec::new(); for proj_entity in projectiles { - let proj_pos = match world.transforms.with(proj_entity, |t| t.position) + let proj_pos = match transforms.with(proj_entity, |t| t.position) { Some(p) => p, None => continue, @@ -43,17 +57,20 @@ pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) let to_player = player_pos - proj_pos; let distance = to_player.length(); - let window_open = world - .dialog_projectiles + let window_open = dialog_projectiles .with(proj_entity, |p| p.parry_window_open) .unwrap_or(false); if window_open { - if let Some(outcome) = resolve_parry(world, proj_entity, input_state, player_is_evading) + if let Some(outcome) = resolve_parry( + dialog_projectiles, + proj_entity, + input_state, + player_is_evading, + ) { - let bubble_entity = world - .dialog_projectiles + let bubble_entity = dialog_projectiles .with(proj_entity, |p| p.bubble_entity) .unwrap(); outcomes.push(DialogOutcomeEvent { @@ -67,8 +84,7 @@ pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) if distance < HIT_RADIUS { - let bubble_entity = world - .dialog_projectiles + let bubble_entity = dialog_projectiles .with(proj_entity, |p| p.bubble_entity) .unwrap(); let outcome = if player_is_evading @@ -89,7 +105,7 @@ pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) if distance < PARRY_WINDOW_RADIUS { - world.dialog_projectiles.with_mut(proj_entity, |p| { + dialog_projectiles.with_mut(proj_entity, |p| { p.parry_window_open = true; }); } @@ -103,14 +119,14 @@ pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) Vec3::ZERO }; - world.transforms.with_mut(proj_entity, |t| { + transforms.with_mut(proj_entity, |t| { t.position += direction * PROJECTILE_SPEED * (1.0 / 60.0); }); - let proj_pos = world.transforms.with(proj_entity, |t| t.position); + let proj_pos = transforms.with(proj_entity, |t| t.position); if let Some(pos) = proj_pos { - world.spawn_particle_intents.push(SpawnParticleIntent { + spawn_particle_intents.push(SpawnParticleIntent { origin: pos, config: projectile_swarm_config(), }); @@ -119,14 +135,16 @@ pub fn dialog_projectile_system(world: &mut World, input_state: &InputState) for entity in to_despawn { - world.despawn(entity); + transforms.remove(entity); + projectile_tags.remove(entity); + dialog_projectiles.remove(entity); } - world.dialog_outcomes.extend(outcomes); + dialog_outcomes.extend(outcomes); } fn resolve_parry( - world: &World, + dialog_projectiles: &Storage, proj_entity: EntityHandle, input_state: &InputState, player_is_evading: bool, @@ -137,9 +155,7 @@ fn resolve_parry( return Some(DialogOutcome::Evaded); } - let correct_parry = world - .dialog_projectiles - .with(proj_entity, |p| p.correct_parry)?; + let correct_parry = dialog_projectiles.with(proj_entity, |p| p.correct_parry)?; if input_state.i_just_pressed { @@ -200,9 +216,3 @@ fn projectile_swarm_config() -> ParticleEmitterConfig color_end: [0.2, 0.05, 0.0, 0.0], } } - -fn is_player_evading(world: &World, player_entity: EntityHandle) -> bool -{ - world.leaping_states.get(player_entity).is_some() - || world.rolling_states.get(player_entity).is_some() -} diff --git a/src/systems/dialog_render.rs b/src/systems/dialog_render.rs index 13198aa..ecef4a2 100644 --- a/src/systems/dialog_render.rs +++ b/src/systems/dialog_render.rs @@ -1,8 +1,10 @@ use glam::{Mat4, Vec3}; +use crate::components::dialog::DialogBubbleComponent; use crate::render::billboard::{BillboardDrawCall, BillboardVertex, BubbleUniforms}; use crate::render::{with_font_atlas, TextVertex}; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; const MAX_BUBBLE_WIDTH: f32 = 8.0; const MIN_BUBBLE_WIDTH: f32 = 0.5; @@ -19,7 +21,9 @@ const TEXT_PADDING: f32 = 0.06; const LINE_SPACING: f32 = 0.01; pub fn dialog_bubble_render_system( - world: &World, + transforms: &Storage, + dialog_bubbles: &Storage, + bubble_tags: &Storage<()>, camera_pos: Vec3, view_proj: Mat4, ) -> (Vec, Vec) @@ -27,17 +31,15 @@ pub fn dialog_bubble_render_system( let mut calls = Vec::new(); let mut all_text: Vec = Vec::new(); - for bubble_entity in world.bubble_tags.all() + for bubble_entity in bubble_tags.all() { - let bubble_pos = match world.transforms.with(bubble_entity, |t| t.position) + let bubble_pos = match transforms.with(bubble_entity, |t| t.position) { Some(p) => p, None => continue, }; - let text = match world - .dialog_bubbles - .with(bubble_entity, |b| b.current_text.clone()) + let text = match dialog_bubbles.with(bubble_entity, |b| b.current_text.clone()) { Some(t) => t, None => continue, @@ -57,7 +59,7 @@ pub fn dialog_bubble_render_system( // Compute body height analytically. // border_world = BORDER_W * body_height (body is the smaller dimension) // body_height = text_h + 2 * (border_world + TEXT_PADDING) - // → body_height * (1 - 2*BORDER_W) = text_h + 2*TEXT_PADDING + // -> body_height * (1 - 2*BORDER_W) = text_h + 2*TEXT_PADDING let text_h = n_lines as f32 * CHAR_WORLD_HEIGHT + n_lines.saturating_sub(1) as f32 * LINE_SPACING; let body_height = (text_h + 2.0 * TEXT_PADDING) / (1.0 - 2.0 * BORDER_W); diff --git a/src/systems/dialog_system.rs b/src/systems/dialog_system.rs index 34c34d5..a36f1fc 100644 --- a/src/systems/dialog_system.rs +++ b/src/systems/dialog_system.rs @@ -2,30 +2,74 @@ use bladeink::story::Story; use glam::Vec3; use crate::components::dialog::{ - DialogBubbleComponent, DialogPhase, DialogProjectileComponent, ParryButton, + DialogBubbleComponent, DialogOutcomeEvent, DialogPhase, DialogProjectileComponent, + DialogSourceComponent, ParryButton, }; -use crate::components::trigger::TriggerEventKind; -use crate::entity::EntityHandle; -use crate::world::{Transform, World}; +use crate::components::trigger::{TriggerEvent, TriggerEventKind}; +use crate::entity::{EntityHandle, EntityManager}; +use crate::utility::transform::Transform; +use crate::world::Storage; const DEFAULT_DISPLAY_TIME: f32 = 3.0; const PARRY_TAG_PREFIX: &str = "parry:"; const TIMER_TAG_PREFIX: &str = "timer:"; -pub fn dialog_system(world: &mut World, delta: f32) +pub fn dialog_system( + entities: &mut EntityManager, + trigger_events: &[TriggerEvent], + dialog_sources: &Storage, + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + transforms: &mut Storage, + names: &mut Storage, + player_tags: &Storage<()>, + projectile_tags: &mut Storage<()>, + dialog_projectiles: &mut Storage, + dialog_outcomes: &mut Vec, + delta: f32, +) { - process_trigger_events(world); - tick_displaying_bubbles(world, delta); - process_outcomes(world); + process_trigger_events( + entities, + trigger_events, + dialog_sources, + bubble_tags, + dialog_bubbles, + transforms, + names, + projectile_tags, + dialog_projectiles, + ); + tick_displaying_bubbles( + entities, + bubble_tags, + dialog_bubbles, + transforms, + player_tags, + projectile_tags, + dialog_projectiles, + delta, + ); + process_outcomes(bubble_tags, dialog_bubbles, dialog_outcomes); } -fn process_trigger_events(world: &mut World) +fn process_trigger_events( + entities: &mut EntityManager, + trigger_events: &[TriggerEvent], + dialog_sources: &Storage, + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + transforms: &mut Storage, + names: &mut Storage, + projectile_tags: &mut Storage<()>, + dialog_projectiles: &mut Storage, +) { - let events: Vec<_> = world.trigger_events.iter().cloned().collect(); + let events: Vec<_> = trigger_events.iter().cloned().collect(); for event in events { - let has_source = world.dialog_sources.get(event.trigger_entity).is_some(); + let has_source = dialog_sources.get(event.trigger_entity).is_some(); if !has_source { continue; @@ -35,9 +79,8 @@ fn process_trigger_events(world: &mut World) { TriggerEventKind::Entered => { - let already_active = world.bubble_tags.all().iter().any(|&b| { - world - .dialog_bubbles + let already_active = bubble_tags.all().iter().any(|&b| { + dialog_bubbles .with(b, |db| db.character_entity == event.trigger_entity) .unwrap_or(false) }); @@ -47,22 +90,43 @@ fn process_trigger_events(world: &mut World) continue; } - spawn_bubble(world, event.trigger_entity); + spawn_bubble( + entities, + dialog_sources, + bubble_tags, + dialog_bubbles, + transforms, + names, + event.trigger_entity, + ); } TriggerEventKind::Exited => { - despawn_bubbles_for_character(world, event.trigger_entity); + despawn_bubbles_for_character( + bubble_tags, + dialog_bubbles, + transforms, + projectile_tags, + dialog_projectiles, + event.trigger_entity, + ); } } } } -fn spawn_bubble(world: &mut World, character_entity: EntityHandle) +fn spawn_bubble( + entities: &mut EntityManager, + dialog_sources: &Storage, + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + transforms: &mut Storage, + names: &mut Storage, + character_entity: EntityHandle, +) { - let ink_json = match world - .dialog_sources - .with(character_entity, |s| s.ink_json.clone()) + let ink_json = match dialog_sources.with(character_entity, |s| s.ink_json.clone()) { Some(json) => json, None => return, @@ -80,21 +144,18 @@ fn spawn_bubble(world: &mut World, character_entity: EntityHandle) let (text, parry, display_time) = advance_story(&mut story); - let character_pos = world - .transforms + let character_pos = transforms .with(character_entity, |t| t.position) .unwrap_or(Vec3::ZERO); - let bubble_entity = world.spawn(); - world.transforms.insert( + let bubble_entity = entities.spawn(); + transforms.insert( bubble_entity, Transform::from_position(character_pos + Vec3::new(0.0, 8.0, 0.0)), ); - world - .names - .insert(bubble_entity, "DialogBubble".to_string()); - world.bubble_tags.insert(bubble_entity, ()); - world.dialog_bubbles.insert( + names.insert(bubble_entity, "DialogBubble".to_string()); + bubble_tags.insert(bubble_entity, ()); + dialog_bubbles.insert( bubble_entity, DialogBubbleComponent { story, @@ -109,14 +170,20 @@ fn spawn_bubble(world: &mut World, character_entity: EntityHandle) ); } -fn despawn_bubbles_for_character(world: &mut World, character_entity: EntityHandle) +fn despawn_bubbles_for_character( + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + transforms: &mut Storage, + projectile_tags: &mut Storage<()>, + dialog_projectiles: &mut Storage, + character_entity: EntityHandle, +) { - let bubbles: Vec = world.bubble_tags.all(); + let bubbles: Vec = bubble_tags.all(); for bubble_entity in bubbles { - let matches = world - .dialog_bubbles + let matches = dialog_bubbles .with(bubble_entity, |b| b.character_entity == character_entity) .unwrap_or(false); @@ -125,26 +192,38 @@ fn despawn_bubbles_for_character(world: &mut World, character_entity: EntityHand continue; } - if let Some(bubble) = world.dialog_bubbles.get(bubble_entity) + if let Some(bubble) = dialog_bubbles.get(bubble_entity) { if let DialogPhase::ProjectileInFlight { projectile_entity } = bubble.phase { - world.despawn(projectile_entity); + transforms.remove(projectile_entity); + projectile_tags.remove(projectile_entity); + dialog_projectiles.remove(projectile_entity); } } - world.despawn(bubble_entity); + transforms.remove(bubble_entity); + bubble_tags.remove(bubble_entity); + dialog_bubbles.remove(bubble_entity); } } -fn tick_displaying_bubbles(world: &mut World, delta: f32) +fn tick_displaying_bubbles( + entities: &mut EntityManager, + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + transforms: &mut Storage, + player_tags: &Storage<()>, + projectile_tags: &mut Storage<()>, + dialog_projectiles: &mut Storage, + delta: f32, +) { - let bubbles: Vec = world.bubble_tags.all(); + let bubbles: Vec = bubble_tags.all(); for bubble_entity in bubbles { - let expired = world - .dialog_bubbles + let expired = dialog_bubbles .with_mut(bubble_entity, |b| { if let DialogPhase::Displaying { ref mut timer } = b.phase { @@ -160,45 +239,37 @@ fn tick_displaying_bubbles(world: &mut World, delta: f32) if expired { - let correct_parry = match world - .dialog_bubbles - .with(bubble_entity, |b| b.correct_parry) + let correct_parry = match dialog_bubbles.with(bubble_entity, |b| b.correct_parry) { Some(Some(p)) => p, _ => { - world.despawn(bubble_entity); + transforms.remove(bubble_entity); + bubble_tags.remove(bubble_entity); + dialog_bubbles.remove(bubble_entity); continue; } }; - let bubble_pos = world - .transforms + let bubble_pos = transforms .with(bubble_entity, |t| t.position) .unwrap_or(Vec3::ZERO); - let player_entity = world - .player_tags + let player_entity = player_tags .all() .into_iter() .next() .expect("no player entity"); - let player_pos = world - .transforms + let player_pos = transforms .with(player_entity, |t| t.position) .unwrap_or(Vec3::ZERO); let velocity = player_pos - bubble_pos; - let projectile_entity = world.spawn(); - world - .transforms - .insert(projectile_entity, Transform::from_position(bubble_pos)); - world - .names - .insert(projectile_entity, "DialogProjectile".to_string()); - world.projectile_tags.insert(projectile_entity, ()); - world.dialog_projectiles.insert( + let projectile_entity = entities.spawn(); + transforms.insert(projectile_entity, Transform::from_position(bubble_pos)); + projectile_tags.insert(projectile_entity, ()); + dialog_projectiles.insert( projectile_entity, DialogProjectileComponent { bubble_entity, @@ -208,29 +279,33 @@ fn tick_displaying_bubbles(world: &mut World, delta: f32) }, ); - world.dialog_bubbles.with_mut(bubble_entity, |b| { + dialog_bubbles.with_mut(bubble_entity, |b| { b.phase = DialogPhase::ProjectileInFlight { projectile_entity }; }); } } } -fn process_outcomes(world: &mut World) +fn process_outcomes( + bubble_tags: &mut Storage<()>, + dialog_bubbles: &mut Storage, + dialog_outcomes: &mut Vec, +) { - let outcomes: Vec<_> = world.dialog_outcomes.drain(..).collect(); + let outcomes: Vec<_> = dialog_outcomes.drain(..).collect(); for event in outcomes { let bubble_entity = event.bubble_entity; - if world.dialog_bubbles.get(bubble_entity).is_none() + if dialog_bubbles.get(bubble_entity).is_none() { continue; } let choice_tag = event.outcome.to_choice_tag(); - let next = world.dialog_bubbles.with_mut(bubble_entity, |b| { + let next = dialog_bubbles.with_mut(bubble_entity, |b| { let choices = b.story.get_current_choices(); let idx = choices .iter() @@ -264,7 +339,7 @@ fn process_outcomes(world: &mut World) { Some(Some((text, parry, display_time))) => { - world.dialog_bubbles.with_mut(bubble_entity, |b| { + dialog_bubbles.with_mut(bubble_entity, |b| { b.current_text = text; b.correct_parry = parry; b.display_time = display_time; @@ -276,7 +351,8 @@ fn process_outcomes(world: &mut World) Some(None) => { - world.despawn(bubble_entity); + bubble_tags.remove(bubble_entity); + dialog_bubbles.remove(bubble_entity); } None => diff --git a/src/systems/follow.rs b/src/systems/follow.rs index c9df64b..4c147b7 100644 --- a/src/systems/follow.rs +++ b/src/systems/follow.rs @@ -1,15 +1,17 @@ -use crate::world::World; +use crate::components::FollowComponent; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn follow_system(world: &mut World) +pub fn follow_system(follows: &mut Storage, transforms: &mut Storage) { - let following_entities: Vec<_> = world.follows.all(); + let following_entities: Vec<_> = follows.all(); for entity in following_entities { - if let Some(follow) = world.follows.get(entity) + if let Some(follow) = follows.get(entity) { let target = follow.target; - if let Some(target_transform) = world.transforms.get(target) + if let Some(target_transform) = transforms.get(target) { let target_pos = target_transform.position; let target_rot = target_transform.rotation; @@ -18,7 +20,7 @@ pub fn follow_system(world: &mut World) let inherit_rot = follow.inherit_rotation; let inherit_scale = follow.inherit_scale; - world.transforms.with_mut(entity, |transform| { + transforms.with_mut(entity, |transform| { transform.position = target_pos; if inherit_rot diff --git a/src/systems/input.rs b/src/systems/input.rs index f314e09..1ce11bc 100644 --- a/src/systems/input.rs +++ b/src/systems/input.rs @@ -1,29 +1,45 @@ use glam::Vec3; +use crate::components::camera::CameraComponent; +use crate::components::FollowComponent; +use crate::components::InputComponent; use crate::utility::input::InputState; -use crate::world::World; +use crate::world::Storage; -pub fn player_input_system(world: &mut World, input_state: &InputState) +pub fn player_input_system( + cameras: &Storage, + follows: &Storage, + player_tags: &Storage<()>, + inputs: &mut Storage, + input_state: &InputState, +) { - if !world.camera_is_following() + let camera_is_following = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, _)| follows.get(*e).is_some()) + .unwrap_or(false); + + if !camera_is_following { return; } - let Some((_, camera)) = world.active_camera() - else + let (_, camera) = match cameras.components.iter().find(|(_, cam)| cam.is_active) { - return; + Some((e, c)) => (*e, c), + None => return, }; let forward = camera.get_forward_horizontal(); let right = camera.get_right_horizontal(); - let players = world.player_tags.all(); + let players = player_tags.all(); for player in players { - world.inputs.with_mut(player, |input_component| { + inputs.with_mut(player, |input_component| { let mut local_input = Vec3::ZERO; if input_state.w diff --git a/src/systems/particle.rs b/src/systems/particle.rs index 8db22db..84c459e 100644 --- a/src/systems/particle.rs +++ b/src/systems/particle.rs @@ -2,7 +2,6 @@ use rand::Rng; use crate::components::particle::{ParticleEmitterConfig, SpawnParticleIntent}; use crate::render::particle_types::ParticleInstanceRaw; -use crate::world::World; pub struct Particle { @@ -92,24 +91,27 @@ fn spawn_from_config( } } -pub fn particle_intent_system(world: &mut World) +pub fn particle_intent_system( + particle_buffers: &mut Option, + spawn_particle_intents: &mut Vec, +) { - if world.particle_buffers.is_none() + if particle_buffers.is_none() { - world.particle_buffers = Some(ParticleBuffers { + *particle_buffers = Some(ParticleBuffers { particles: Vec::new(), instances: Vec::new(), emit_accumulator: 0.0, }); } - let intents: Vec = world.spawn_particle_intents.drain(..).collect(); + let intents: Vec = spawn_particle_intents.drain(..).collect(); if intents.is_empty() { return; } - let buffers = world.particle_buffers.as_mut().unwrap(); + let buffers = particle_buffers.as_mut().unwrap(); let mut rng = rand::rng(); for intent in intents { @@ -117,9 +119,9 @@ pub fn particle_intent_system(world: &mut World) } } -pub fn particle_update_system(world: &mut World, delta: f32) +pub fn particle_update_system(particle_buffers: &mut Option, delta: f32) { - let Some(ref mut buffers) = world.particle_buffers + let Some(ref mut buffers) = particle_buffers else { return; diff --git a/src/systems/physics_sync.rs b/src/systems/physics_sync.rs index 0addf0b..ac004c7 100644 --- a/src/systems/physics_sync.rs +++ b/src/systems/physics_sync.rs @@ -1,21 +1,27 @@ +use crate::components::PhysicsComponent; +use crate::entity::EntityManager; use crate::physics::PhysicsManager; use crate::utility::transform::Transform; -use crate::world::World; +use crate::world::Storage; -pub fn physics_sync_system(world: &mut World) +pub fn physics_sync_system( + entities: &EntityManager, + physics: &Storage, + transforms: &mut Storage, +) { - let all_entities = world.entities.all_entities(); + let all_entities = entities.all_entities(); for entity in all_entities { - if let Some(physics) = world.physics.get(entity) + if let Some(physics) = physics.get(entity) { if let Some(rigidbody_position) = PhysicsManager::get_rigidbody_position(physics.rigidbody) { let transform = Transform::from(rigidbody_position); - world.transforms.with_mut(entity, |t| { + transforms.with_mut(entity, |t| { *t = transform; }); } diff --git a/src/systems/render.rs b/src/systems/render.rs index dafec63..42cb42b 100644 --- a/src/systems/render.rs +++ b/src/systems/render.rs @@ -1,17 +1,25 @@ +use crate::components::{DissolveComponent, MeshComponent}; +use crate::entity::EntityManager; use crate::loaders::mesh::InstanceRaw; use crate::render::DrawCall; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; use bytemuck::cast_slice; -pub fn render_system(world: &World) -> Vec +pub fn render_system( + entities: &EntityManager, + transforms: &Storage, + meshes: &Storage, + dissolves: &Storage, +) -> Vec { - let all_entities = world.entities.all_entities(); + let all_entities = entities.all_entities(); all_entities .iter() .filter_map(|&entity| { - let transform = world.transforms.get(entity)?; - let mesh_component = world.meshes.get(entity)?; + let transform = transforms.get(entity)?; + let mesh_component = meshes.get(entity)?; let model_matrix = transform.to_matrix(); @@ -22,7 +30,7 @@ pub fn render_system(world: &World) -> Vec } else { - let dissolve_amount = world.dissolves.get(entity).map(|d| d.amount).unwrap_or(0.0); + let dissolve_amount = dissolves.get(entity).map(|d| d.amount).unwrap_or(0.0); let instance_data = InstanceRaw { model: model_matrix.to_cols_array_2d(), diff --git a/src/systems/rotate.rs b/src/systems/rotate.rs index 353ec67..e5cd4d0 100644 --- a/src/systems/rotate.rs +++ b/src/systems/rotate.rs @@ -1,18 +1,24 @@ use glam::Quat; -use crate::world::World; +use crate::components::RotateComponent; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn rotate_system(world: &mut World, delta: f32) +pub fn rotate_system( + rotates: &Storage, + transforms: &mut Storage, + delta: f32, +) { - let entities = world.rotates.all(); + let entities = rotates.all(); for entity in entities { - if let Some(rotate) = world.rotates.get(entity) + if let Some(rotate) = rotates.get(entity) { let rotation_delta = Quat::from_axis_angle(rotate.axis, rotate.speed * delta); - world.transforms.with_mut(entity, |transform| { + transforms.with_mut(entity, |transform| { transform.rotation = rotation_delta * transform.rotation; }); } diff --git a/src/systems/snow.rs b/src/systems/snow.rs index 8b9c7dd..54a2412 100644 --- a/src/systems/snow.rs +++ b/src/systems/snow.rs @@ -1,11 +1,40 @@ -use crate::world::World; +use crate::components::camera::CameraComponent; +use crate::components::FollowComponent; +use crate::render::snow::SnowLayer; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn snow_system(world: &mut World) +pub fn snow_system( + cameras: &Storage, + transforms: &Storage, + player_tags: &Storage<()>, + follows: &Storage, + snow_layer: &mut Option, +) { - let camera_pos = world.active_camera_position(); - let player_pos = world.player_position(); - let is_following = world.camera_is_following(); - if let Some(ref mut snow_layer) = world.snow_layer + let camera_pos = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .and_then(|(e, _)| transforms.get(*e)) + .map(|t| t.position) + .unwrap_or(glam::Vec3::ZERO); + + let player_pos = player_tags + .all() + .first() + .and_then(|e| transforms.get(*e)) + .map(|t| t.position) + .unwrap_or(glam::Vec3::ZERO); + + let is_following = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, _)| follows.get(*e).is_some()) + .unwrap_or(false); + + if let Some(ref mut snow_layer) = snow_layer { if is_following { diff --git a/src/systems/spotlight_sync.rs b/src/systems/spotlight_sync.rs index fa57e3f..85e6662 100644 --- a/src/systems/spotlight_sync.rs +++ b/src/systems/spotlight_sync.rs @@ -1,23 +1,28 @@ +use crate::components::lights::spot::SpotlightComponent; use crate::render::Spotlight; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn spotlight_sync_system(world: &World) -> Vec +pub fn spotlight_sync_system( + spotlights: &Storage, + transforms: &Storage, +) -> Vec { - let mut entities = world.spotlights.all(); + let mut entities = spotlights.all(); entities.sort(); - let mut spotlights = Vec::new(); + let mut result = Vec::new(); for entity in entities { - if let Some(spotlight_component) = world.spotlights.get(entity) + if let Some(spotlight_component) = spotlights.get(entity) { - if let Some(transform) = world.transforms.get(entity) + if let Some(transform) = transforms.get(entity) { let position = transform.position + spotlight_component.offset; let direction = transform.rotation * spotlight_component.direction; - spotlights.push(Spotlight::new( + result.push(Spotlight::new( position, direction, spotlight_component.inner_angle, @@ -28,5 +33,5 @@ pub fn spotlight_sync_system(world: &World) -> Vec } } - spotlights + result } diff --git a/src/systems/tree_dissolve.rs b/src/systems/tree_dissolve.rs index 86f4a66..a738e4c 100644 --- a/src/systems/tree_dissolve.rs +++ b/src/systems/tree_dissolve.rs @@ -1,12 +1,15 @@ +use crate::components::camera::CameraComponent; +use crate::components::tree_instances::TreeInstancesComponent; use crate::loaders::mesh::InstanceRaw; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; use bytemuck::cast_slice; -pub fn tree_dissolve_update_system(world: &mut World, delta: f32) +pub fn tree_dissolve_update_system(tree_instances: &mut Storage, delta: f32) { - for entity in world.tree_instances.all() + for entity in tree_instances.all() { - if let Some(tree_instances) = world.tree_instances.get_mut(entity) + if let Some(tree_instances) = tree_instances.get_mut(entity) { for i in 0..tree_instances.dissolve_amounts.len() { @@ -20,15 +23,24 @@ pub fn tree_dissolve_update_system(world: &mut World, delta: f32) } } -pub fn tree_occlusion_system(world: &mut World) +pub fn tree_occlusion_system( + player_tags: &Storage<()>, + transforms: &Storage, + cameras: &Storage, + tree_instances: &mut Storage, +) { - let player_entity = world.player_tags.all().first().copied(); - let player_pos = player_entity.and_then(|e| world.transforms.get(e).map(|t| t.position)); + let player_entity = player_tags.all().first().copied(); + let player_pos = player_entity.and_then(|e| transforms.get(e).map(|t| t.position)); if let Some(player_pos) = player_pos { - let camera_entity = world.active_camera().map(|(e, _)| e); - let camera_pos = camera_entity.and_then(|e| world.transforms.get(e).map(|t| t.position)); + let camera_entity = cameras + .components + .iter() + .find(|(_, cam)| cam.is_active) + .map(|(e, _)| *e); + let camera_pos = camera_entity.and_then(|e| transforms.get(e).map(|t| t.position)); if let Some(camera_pos) = camera_pos { @@ -43,9 +55,9 @@ pub fn tree_occlusion_system(world: &mut World) let to_player_normalized = to_player.normalize(); let occlusion_radius = 10.0; - for tree_entity in world.tree_instances.all() + for tree_entity in tree_instances.all() { - if let Some(tree_instances) = world.tree_instances.get_mut(tree_entity) + if let Some(tree_instances) = tree_instances.get_mut(tree_entity) { for (idx, instance) in tree_instances.instances.iter().enumerate() { @@ -81,11 +93,11 @@ pub fn tree_occlusion_system(world: &mut World) } } -pub fn tree_instance_buffer_update_system(world: &mut World) +pub fn tree_instance_buffer_update_system(tree_instances: &Storage) { - for entity in world.tree_instances.all() + for entity in tree_instances.all() { - if let Some(tree_instances) = world.tree_instances.get(entity) + if let Some(tree_instances) = tree_instances.get(entity) { let instance_data_vec: Vec = tree_instances .instances diff --git a/src/systems/trigger.rs b/src/systems/trigger.rs index 019498f..daf7029 100644 --- a/src/systems/trigger.rs +++ b/src/systems/trigger.rs @@ -1,41 +1,47 @@ use glam::Vec3; use crate::components::trigger::{ - TriggerEvent, TriggerEventKind, TriggerFilter, TriggerShape, TriggerState, + TriggerComponent, TriggerEvent, TriggerEventKind, TriggerFilter, TriggerShape, TriggerState, }; use crate::entity::EntityHandle; -use crate::world::World; +use crate::utility::transform::Transform; +use crate::world::Storage; -pub fn trigger_system(world: &mut World) +pub fn trigger_system( + trigger_events: &mut Vec, + triggers: &mut Storage, + transforms: &Storage, + player_tags: &Storage<()>, +) { - world.trigger_events.clear(); + trigger_events.clear(); - let trigger_entities: Vec = world.triggers.all(); + let trigger_entities: Vec = triggers.all(); let mut pending_events: Vec = Vec::new(); for trigger_entity in trigger_entities { - let trigger_pos = match world.transforms.get(trigger_entity) + let trigger_pos = match transforms.get(trigger_entity) { Some(t) => t.position, None => continue, }; - let candidate_entities: Vec = match world.triggers.get(trigger_entity) + let candidate_entities: Vec = match triggers.get(trigger_entity) { Some(trigger) => match &trigger.filter { - TriggerFilter::Player => world.player_tags.all(), + TriggerFilter::Player => player_tags.all(), }, None => continue, }; let activator_positions: Vec<(EntityHandle, Vec3)> = candidate_entities .into_iter() - .filter_map(|e| world.transforms.get(e).map(|t| (e, t.position))) + .filter_map(|e| transforms.get(e).map(|t| (e, t.position))) .collect(); - let overlapping = match world.triggers.get(trigger_entity) + let overlapping = match triggers.get(trigger_entity) { Some(trigger) => activator_positions .iter() @@ -48,7 +54,7 @@ pub fn trigger_system(world: &mut World) let first_activator = activator_positions.first().map(|(e, _)| *e); - if let Some(trigger) = world.triggers.get_mut(trigger_entity) + if let Some(trigger) = triggers.get_mut(trigger_entity) { match (&trigger.state, overlapping) { @@ -82,5 +88,5 @@ pub fn trigger_system(world: &mut World) } } - world.trigger_events.extend(pending_events); + trigger_events.extend(pending_events); }