Skip to content

Commit e3031a8

Browse files
committed
feat: add road logistics
1 parent 6796096 commit e3031a8

11 files changed

Lines changed: 202 additions & 9 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:05855e354a8aa55e8c36821323fa82aba7dc3ddad079a22fb6e13bd6f7960576
3+
size 670
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:053551e81314683a7207feb99b72dc5c4772d9bff5b87cd3ecd70d1a006bee8e
3+
size 609

assets/sprites/logistics/path.png

Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use bevy::prelude::*;
2+
3+
use crate::gameplay::{
4+
FactorySystems,
5+
logistics::path::Pathable,
6+
world::terrain::{Terrain, Worldly},
7+
y_sort::YSort,
8+
};
9+
10+
pub(super) fn plugin(app: &mut App) {
11+
app.add_systems(
12+
Update,
13+
spawn_intersection
14+
.in_set(FactorySystems::Build)
15+
.run_if(on_event::<Pointer<Click>>),
16+
);
17+
}
18+
19+
fn spawn_intersection(
20+
mut events: EventReader<Pointer<Click>>,
21+
terrain: Single<Entity, With<Terrain>>,
22+
asset_server: Res<AssetServer>,
23+
mut commands: Commands,
24+
) {
25+
for event in events.read() {
26+
if event.target != *terrain {
27+
continue;
28+
}
29+
30+
if event.button != PointerButton::Middle {
31+
continue;
32+
}
33+
34+
commands.spawn((
35+
Name::new("Intersection"),
36+
Transform::from_translation(event.hit.position.unwrap_or_default()),
37+
Sprite::from_image(asset_server.load("sprites/logistics/intersection.png")),
38+
Worldly,
39+
Pathable::walkable(),
40+
Pickable::default(),
41+
YSort::default(),
42+
));
43+
}
44+
}

src/gameplay/logistics/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
use bevy::prelude::*;
22

3-
pub(super) fn plugin(_app: &mut App) {}
3+
pub mod intersection;
4+
pub mod path;
5+
6+
pub(super) fn plugin(app: &mut App) {
7+
app.add_plugins((intersection::plugin, path::plugin));
8+
}

src/gameplay/logistics/path.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use bevy::{platform::collections::HashSet, prelude::*};
2+
3+
use crate::gameplay::{FactorySystems, world::terrain::Worldly, y_sort::YSort};
4+
5+
pub(super) fn plugin(app: &mut App) {
6+
app.register_type::<Path>();
7+
app.register_type::<Pathable>();
8+
9+
app.add_systems(
10+
Update,
11+
(build_paths,)
12+
.in_set(FactorySystems::Build)
13+
.run_if(on_event::<Pointer<DragDrop>>),
14+
);
15+
16+
app.register_type::<PathGraph>()
17+
.init_resource::<PathGraph>()
18+
.add_systems(
19+
Update,
20+
(add_nodes_to_graph, add_edges_to_graph).in_set(FactorySystems::Logistics),
21+
);
22+
}
23+
24+
#[derive(Resource, Reflect, Default)]
25+
#[reflect(Resource)]
26+
pub struct PathGraph {
27+
nodes: HashSet<Entity>,
28+
edges: HashSet<(Entity, Entity)>,
29+
}
30+
31+
fn add_nodes_to_graph(query: Query<Entity, Added<Pathable>>, mut graph: ResMut<PathGraph>) {
32+
for entity in query {
33+
graph.nodes.insert(entity);
34+
}
35+
}
36+
37+
fn add_edges_to_graph(query: Query<&Path, Added<Path>>, mut graph: ResMut<PathGraph>) {
38+
for path in query {
39+
graph.edges.insert((path.0, path.1));
40+
}
41+
}
42+
43+
#[derive(Component, Reflect)]
44+
#[reflect(Component)]
45+
pub struct Path(Entity, Entity);
46+
47+
#[derive(Component, Reflect, Default)]
48+
#[reflect(Component)]
49+
pub struct Pathable {
50+
pub walkable: bool,
51+
}
52+
53+
impl Pathable {
54+
pub fn walkable() -> Self {
55+
Self { walkable: true }
56+
}
57+
}
58+
59+
fn build_paths(
60+
mut events: EventReader<Pointer<DragDrop>>,
61+
asset_server: Res<AssetServer>,
62+
mut commands: Commands,
63+
pathables: Query<Entity, With<Pathable>>,
64+
transforms: Query<&Transform>,
65+
) {
66+
for event in events.read() {
67+
let target = event.target;
68+
let dropped = event.dropped;
69+
70+
if !pathables.contains(target) || !pathables.contains(dropped) {
71+
continue;
72+
}
73+
74+
let Ok(from) = transforms.get(target) else {
75+
continue;
76+
};
77+
78+
let Ok(to) = transforms.get(dropped) else {
79+
continue;
80+
};
81+
82+
let direction = to.translation - from.translation;
83+
let rotation = Quat::from_rotation_z(direction.xy().to_angle());
84+
85+
commands.spawn((
86+
Name::new("Path"),
87+
Path(target, dropped),
88+
Worldly,
89+
Transform::default()
90+
.with_translation(from.translation.midpoint(to.translation))
91+
.with_rotation(rotation),
92+
Sprite {
93+
image: asset_server.load("sprites/logistics/path.png"),
94+
custom_size: Some(Vec2::new(
95+
to.translation.distance(from.translation) - 64.0,
96+
32.0,
97+
)),
98+
image_mode: SpriteImageMode::Sliced(TextureSlicer {
99+
border: BorderRect {
100+
left: 16.0,
101+
right: 16.0,
102+
top: 0.0,
103+
bottom: 0.0,
104+
},
105+
center_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
106+
sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
107+
max_corner_scale: 1.0,
108+
}),
109+
..default()
110+
},
111+
YSort(0.5),
112+
));
113+
}
114+
}

src/gameplay/structure/build.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
assets::StructureDef,
1616
interactable::{Interact, Interactable},
1717
},
18-
world::{deposit::DepositRecipe, terrain::Terrain},
18+
world::{deposit::DepositRecipe, terrain::Worldly},
1919
y_sort::YSort,
2020
},
2121
};
@@ -42,7 +42,6 @@ pub struct Preview;
4242
fn on_hotbar_selection(
4343
trigger: Trigger<HotbarItemSelected>,
4444
mut commands: Commands,
45-
terrain: Single<Entity, With<Terrain>>,
4645
existing_preview: Option<Single<Entity, With<Preview>>>,
4746
asset_server: Res<AssetServer>,
4847
) {
@@ -52,7 +51,7 @@ fn on_hotbar_selection(
5251

5352
commands.spawn((
5453
Preview,
55-
ChildOf(*terrain),
54+
Worldly,
5655
Sprite::from_color(Color::WHITE.with_alpha(0.5), Vec2::splat(64.0)),
5756
AseAnimation {
5857
aseprite: asset_server.load(format!("sprites/structures/{}.aseprite", trigger.0)),
@@ -83,7 +82,6 @@ fn spawn_structures(
8382
asset_server: Res<AssetServer>,
8483
structure_definitions: Res<Assets<StructureDef>>,
8584
structure_index: Res<IndexMap<StructureDef>>,
86-
terrain: Single<Entity, With<Terrain>>,
8785
deposit_recipes: Query<&DepositRecipe>,
8886
) {
8987
for event in events.read() {
@@ -99,7 +97,7 @@ fn spawn_structures(
9997
Name::new(structure.name.clone()),
10098
// position
10199
Transform::from_translation(event.position.extend(1.0)),
102-
ChildOf(*terrain),
100+
Worldly,
103101
// appearance
104102
Sprite::sized(Vec2::splat(64.0)),
105103
AseAnimation {

src/gameplay/structure/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use bevy::prelude::*;
22

3+
use crate::gameplay::logistics::path::Pathable;
4+
35
pub mod assets;
46
pub mod build;
57
pub mod dismantle;
@@ -20,4 +22,5 @@ pub fn plugin(app: &mut App) {
2022

2123
#[derive(Component, Reflect)]
2224
#[reflect(Component)]
25+
#[require(Pathable)]
2326
pub struct Structure;

src/gameplay/world/deposit.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
assets::{loaders::toml::TomlAssetPlugin, tracking::LoadResource},
88
gameplay::{
99
structure::interactable::Interactable,
10-
world::{MAP_SIZE, WorldSpawnSystems, terrain::Terrain},
10+
world::{MAP_SIZE, WorldSpawnSystems, terrain::Worldly},
1111
y_sort::YSort,
1212
},
1313
screens::Screen,
@@ -57,7 +57,6 @@ pub struct DepositRecipe(pub String);
5757

5858
fn spawn_deposits(
5959
mut commands: Commands,
60-
terrain: Single<Entity, With<Terrain>>,
6160
deposit_assets: Res<DepositAssets>,
6261
deposit_definitions: Res<Assets<DepositDef>>,
6362
) {
@@ -72,7 +71,7 @@ fn spawn_deposits(
7271
rng.random_range(0.0..MAP_SIZE) - MAP_SIZE / 2.0,
7372
1.0,
7473
),
75-
ChildOf(*terrain),
74+
Worldly,
7675
YSort(0.1),
7776
Sprite::sized(Vec2::splat(64.0)),
7877
AseSlice {

0 commit comments

Comments
 (0)