Skip to content

Commit

Permalink
Use dedicated component to control alpha color
Browse files Browse the repository at this point in the history
  • Loading branch information
Shatur committed Dec 14, 2024
1 parent 9f8d799 commit b0fc1e0
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 71 deletions.
53 changes: 53 additions & 0 deletions base/src/alpha_color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::iter;

use bevy::prelude::*;

use crate::game_world::{family::FamilyMode, WorldState};

pub(super) struct AlphaColorPlugin;

impl Plugin for AlphaColorPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
PostUpdate,
Self::update_materials
.run_if(in_state(WorldState::City).or_else(in_state(FamilyMode::Building))),
);
}
}

impl AlphaColorPlugin {
pub(super) fn update_materials(
mut materials: ResMut<Assets<StandardMaterial>>,
ghosts: Query<(Entity, &AlphaColor), Changed<AlphaColor>>,
children: Query<&Children>,
mut material_handles: Query<&mut Handle<StandardMaterial>>,
) {
let Ok((entity, &alpha)) = ghosts.get_single() else {
return;
};

debug!("setting alpha to `{alpha:?}`");
let mut iter = material_handles
.iter_many_mut(iter::once(entity).chain(children.iter_descendants(entity)));
while let Some(mut material_handle) = iter.fetch_next() {
let material = materials
.get(&*material_handle)
.expect("material handle should be valid");

// If color matches, assume that we don't need any update.
if material.base_color == *alpha {
return;
}

let mut material = material.clone();
material.base_color = *alpha;
material.alpha_mode = AlphaMode::Add;
*material_handle = materials.add(material);
}
}
}

/// Blends material texture with the given color.
#[derive(Component, Clone, Copy, Debug, Deref, DerefMut)]
pub(super) struct AlphaColor(pub(super) Color);
35 changes: 15 additions & 20 deletions base/src/game_world/city/road/placing_road.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bevy_enhanced_input::prelude::*;

use super::{Road, RoadData, RoadTool};
use crate::{
alpha_color::{AlphaColor, AlphaColorPlugin},
asset::info::road_info::RoadInfo,
common_conditions::observer_in_state,
game_world::{
Expand All @@ -34,9 +35,13 @@ impl Plugin for PlacingRoadPlugin {
.observe(Self::delete)
.observe(Self::cancel)
.observe(Self::confirm)
.add_systems(Update, Self::update_end.run_if(in_state(CityMode::Roads)))
.add_systems(
Update,
(Self::update_end, Self::update_material).run_if(in_state(CityMode::Roads)),
PostUpdate,
Self::update_alpha
.before(AlphaColorPlugin::update_materials)
.after(PhysicsSet::StepSimulation)
.run_if(in_state(CityMode::Roads)),
);
}
}
Expand Down Expand Up @@ -139,33 +144,21 @@ impl PlacingRoadPlugin {
});
}

fn update_material(
mut materials: ResMut<Assets<StandardMaterial>>,
fn update_alpha(
mut placing_roads: Query<
(&mut Handle<StandardMaterial>, &CollidingEntities),
(&mut AlphaColor, &CollidingEntities),
(Changed<CollidingEntities>, With<PlacingRoad>),
>,
) {
let Ok((mut material_handle, colliding_entities)) = placing_roads.get_single_mut() else {
let Ok((mut alpha, colliding_entities)) = placing_roads.get_single_mut() else {
return;
};

let mut material = materials
.get(&*material_handle)
.cloned()
.expect("material handle should be valid");

let color = if colliding_entities.is_empty() {
WHITE.into()
if colliding_entities.is_empty() {
**alpha = WHITE.into();
} else {
RED.into()
**alpha = RED.into();
};
debug!("changing base color to `{color:?}`");

material.alpha_mode = AlphaMode::Add;
material.base_color = color;

*material_handle = materials.add(material);
}

fn update_end(
Expand Down Expand Up @@ -309,6 +302,7 @@ struct PlacingRoadBundle {
road_data: RoadData,
segment: SplineSegment,
state_scoped: StateScoped<RoadTool>,
alpha: AlphaColor,
collider: Collider,
collision_layers: CollisionLayers,
no_culling: NoFrustumCulling,
Expand All @@ -333,6 +327,7 @@ impl PlacingRoadBundle {
placing_road,
segment: SplineSegment(segment),
state_scoped: StateScoped(tool),
alpha: AlphaColor(WHITE.into()),
collider: Default::default(),
collision_layers: CollisionLayers::new(
Layer::PlacingRoad,
Expand Down
36 changes: 17 additions & 19 deletions base/src/game_world/family/building/wall/placing_wall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bevy_enhanced_input::prelude::*;

use super::{Wall, WallCommand, WallMaterial, WallTool};
use crate::{
alpha_color::{AlphaColor, AlphaColorPlugin},
common_conditions::observer_in_state,
game_world::{
city::ActiveCity,
Expand Down Expand Up @@ -36,7 +37,14 @@ impl Plugin for PlacingWallPlugin {
.observe(Self::confirm)
.add_systems(
Update,
(Self::update_end, Self::update_material).run_if(in_state(BuildingMode::Walls)),
Self::update_end.run_if(in_state(BuildingMode::Walls)),
)
.add_systems(
PostUpdate,
Self::update_alpha
.before(AlphaColorPlugin::update_materials)
.after(PhysicsSet::StepSimulation)
.run_if(in_state(BuildingMode::Walls)),
);
}
}
Expand Down Expand Up @@ -119,33 +127,21 @@ impl PlacingWallPlugin {
});
}

fn update_material(
mut materials: ResMut<Assets<StandardMaterial>>,
fn update_alpha(
mut placing_walls: Query<
(&mut Handle<StandardMaterial>, &CollidingEntities),
(&mut AlphaColor, &CollidingEntities),
(Changed<CollidingEntities>, With<PlacingWall>),
>,
) {
let Ok((mut material_handle, colliding_entities)) = placing_walls.get_single_mut() else {
let Ok((mut alpha, colliding_entities)) = placing_walls.get_single_mut() else {
return;
};

let mut material = materials
.get(&*material_handle)
.cloned()
.expect("material should be preloaded");

let color = if colliding_entities.is_empty() {
WHITE.into()
if colliding_entities.is_empty() {
**alpha = WHITE.into();
} else {
RED.into()
**alpha = RED.into();
};
debug!("changing base color to `{color:?}`");

material.alpha_mode = AlphaMode::Add;
material.base_color = color;

*material_handle = materials.add(material);
}

fn update_end(
Expand Down Expand Up @@ -274,6 +270,7 @@ struct PlacingWallBundle {
placing_wall: PlacingWall,
segment: SplineSegment,
picked: Picked,
alpha: AlphaColor,
state_scoped: StateScoped<WallTool>,
apertures: Apertures,
collider: Collider,
Expand All @@ -298,6 +295,7 @@ impl PlacingWallBundle {
placing_wall,
segment,
picked: Picked,
alpha: AlphaColor(WHITE.into()),
state_scoped: StateScoped(tool),
apertures: Default::default(),
collider: Default::default(),
Expand Down
45 changes: 13 additions & 32 deletions base/src/game_world/object/placing_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use bevy::{
color::palettes::css::{RED, WHITE},
ecs::reflect::ReflectCommandExt,
prelude::*,
scene,
};
use bevy_enhanced_input::prelude::*;

use crate::{
alpha_color::{AlphaColor, AlphaColorPlugin},
asset::info::object_info::ObjectInfo,
common_conditions::observer_in_state,
game_world::{
Expand Down Expand Up @@ -57,9 +57,10 @@ impl Plugin for PlacingObjectPlugin {
.run_if(in_state(CityMode::Objects).or_else(in_state(BuildingMode::Objects))),
)
.add_systems(
SpawnScene,
Self::update_materials
.after(scene::scene_spawner_system)
PostUpdate,
Self::update_alpha
.before(AlphaColorPlugin::update_materials)
.after(PhysicsSet::StepSimulation)
.run_if(in_state(CityMode::Objects).or_else(in_state(BuildingMode::Objects))),
);
}
Expand Down Expand Up @@ -141,6 +142,7 @@ impl PlacingObjectPlugin {
StateScoped(BuildingMode::Objects),
StateScoped(CityMode::Objects),
Picked,
AlphaColor(WHITE.into()),
scene_handle,
PlacingObjectState::new(cursor_offset),
ObjectRotationLimit::default(),
Expand Down Expand Up @@ -319,42 +321,21 @@ impl PlacingObjectPlugin {
}
}

fn update_materials(
mut materials: ResMut<Assets<StandardMaterial>>,
placing_objects: Query<
(Entity, &PlacingObjectState, &CollidingEntities),
fn update_alpha(
mut placing_objects: Query<
(&mut AlphaColor, &PlacingObjectState, &CollidingEntities),
Or<(Changed<CollidingEntities>, Changed<PlacingObjectState>)>,
>,
children: Query<&Children>,
mut material_handles: Query<&mut Handle<StandardMaterial>>,
) {
let Ok((placing_entity, state, colliding_entities)) = placing_objects.get_single() else {
let Ok((mut alpha, state, colliding_entities)) = placing_objects.get_single_mut() else {
return;
};

let color = if state.allowed_place && colliding_entities.is_empty() {
WHITE.into()
if state.allowed_place && colliding_entities.is_empty() {
**alpha = WHITE.into();
} else {
RED.into()
**alpha = RED.into();
};
debug!("changing base color to `{color:?}`");

let mut iter = material_handles.iter_many_mut(children.iter_descendants(placing_entity));
while let Some(mut material_handle) = iter.fetch_next() {
let material = materials
.get(&*material_handle)
.expect("material handle should be valid");

// If color matches, assume that we don't need any update.
if material.base_color == color {
return;
}

let mut material = material.clone();
material.base_color = color;
material.alpha_mode = AlphaMode::Add;
*material_handle = materials.add(material);
}
}

fn ensure_single(
Expand Down
3 changes: 3 additions & 0 deletions base/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod alpha_color;
pub mod asset;
mod combined_scene_collider;
pub mod common_conditions;
Expand All @@ -13,6 +14,7 @@ pub mod settings;

use bevy::{app::PluginGroupBuilder, prelude::*};

use alpha_color::AlphaColorPlugin;
use asset::AssetPlugin;
use combined_scene_collider::SceneColliderConstructorPlugin;
use core::CorePlugin;
Expand All @@ -30,6 +32,7 @@ impl PluginGroup for CorePlugins {
.add(AssetPlugin)
.add(MathPlugin)
.add(CorePlugin)
.add(AlphaColorPlugin)
.add(SceneColliderConstructorPlugin)
.add(GameWorldPlugin)
.add(ErrorReportPlugin)
Expand Down

0 comments on commit b0fc1e0

Please sign in to comment.