Skip to content

Commit 44f1c3f

Browse files
authored
feat: add road logistics (#28)
1 parent 6796096 commit 44f1c3f

File tree

11 files changed

+182
-9
lines changed

11 files changed

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

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

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)