Skip to content

Commit 1003bb2

Browse files
committed
The great componentification
1 parent 542259a commit 1003bb2

File tree

12 files changed

+202
-186
lines changed

12 files changed

+202
-186
lines changed

src/animation/transition.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use pyri_state::prelude::*;
33

44
use crate::core::PostColorSet;
55
use crate::screen::Screen;
6-
use crate::util::despawn::LateDespawn;
76
use crate::util::prelude::*;
87

98
pub(super) fn plugin(app: &mut App) {

src/game/actor.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ use crate::game::actor::movement::OldMovementController;
2727
use crate::game::card::deck::Deck;
2828
use crate::game::combat::death::DespawnOnDeath;
2929
use crate::game::combat::hit::Hurtbox;
30+
use crate::game::level::xp::Xp;
3031
use crate::game::level::xp::XpReward;
32+
use crate::game::level::Level;
3133
use crate::game::sprite::SpriteAnimation;
3234
use crate::util::prelude::*;
3335

@@ -138,8 +140,8 @@ impl EntityCommand for Actor {
138140
// TODO: Death animation instead, despawn when it's finished.
139141
DespawnOnDeath,
140142
),
141-
self.xp_reward,
142-
self.deck,
143+
// Inventory:
144+
(Level::default(), Xp::default(), self.xp_reward, self.deck),
143145
))
144146
.with_children(|children| {
145147
children

src/game/card/deck.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,7 @@ fn advance_deck(
9595

9696
#[derive(Component, Reflect)]
9797
#[reflect(Component)]
98-
struct IsDeckDisplay {
99-
target: Entity,
100-
}
98+
struct IsDeckDisplay;
10199

102100
impl Configure for IsDeckDisplay {
103101
fn configure(app: &mut App) {
@@ -112,14 +110,6 @@ impl Configure for IsDeckDisplay {
112110
}
113111
}
114112

115-
impl Default for IsDeckDisplay {
116-
fn default() -> Self {
117-
Self {
118-
target: Entity::PLACEHOLDER,
119-
}
120-
}
121-
}
122-
123113
/// Clear deck display on any change.
124114
fn clear_deck_display(
125115
mut commands: Commands,
@@ -171,7 +161,8 @@ pub fn deck_display(player: Entity) -> impl EntityCommand {
171161
},
172162
..default()
173163
},
174-
IsDeckDisplay { target: player },
164+
IsDeckDisplay,
165+
Selection(player),
175166
));
176167
}
177168
}

src/game/level.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ pub struct LevelData {
3737
pub xp_cost: f32,
3838
}
3939

40-
#[derive(Resource, Reflect, Default)]
41-
#[reflect(Resource)]
40+
#[derive(Component, Reflect, Default)]
41+
#[reflect(Component)]
4242
pub struct Level {
4343
/// The current level.
4444
pub current: usize,
@@ -49,7 +49,6 @@ pub struct Level {
4949
impl Configure for Level {
5050
fn configure(app: &mut App) {
5151
app.register_type::<Self>();
52-
app.init_resource::<Self>();
5352
}
5453
}
5554

@@ -65,13 +64,14 @@ impl Configure for IsLevelIndicator {
6564
}
6665

6766
fn update_level_indicator(
68-
level: Res<Level>,
69-
mut indicator_query: Query<&mut Text, With<IsLevelIndicator>>,
67+
mut indicator_query: Query<(&mut Text, &Selection), With<IsLevelIndicator>>,
68+
level_query: Query<&Level>,
7069
) {
71-
let level = level.current + level.up;
72-
let level = level.to_string();
70+
for (mut text, selection) in &mut indicator_query {
71+
let level = c!(level_query.get(selection.0));
72+
let level = level.current + level.up;
73+
let level = level.to_string();
7374

74-
for mut text in &mut indicator_query {
7575
for section in &mut text.sections {
7676
section.value.clone_from(&level);
7777
}

src/game/level/up.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ pub(super) fn plugin(app: &mut App) {
1111
app.configure::<LevelUp>();
1212
}
1313

14-
/// A buffered event sent when the player levels up.
14+
/// A buffered event sent when an actor levels up.
1515
#[derive(Event)]
16-
pub struct LevelUp;
16+
pub struct LevelUp(#[allow(unused)] Entity);
1717

1818
impl Configure for LevelUp {
1919
fn configure(app: &mut App) {
@@ -32,29 +32,37 @@ impl Configure for LevelUp {
3232

3333
fn update_level_up_from_xp(
3434
config: ConfigRef<LevelConfig>,
35-
mut level: ResMut<Level>,
36-
mut xp: ResMut<Xp>,
35+
mut level_query: Query<(&mut Level, &mut Xp)>,
3736
) {
3837
let config = r!(config.get());
3938
if config.levels.is_empty() {
4039
return;
4140
}
4241

43-
loop {
44-
let xp_cost = config.level(level.current + level.up).xp_cost;
45-
if xp.0 < xp_cost {
46-
break;
47-
}
42+
for (mut level, mut xp) in &mut level_query {
43+
loop {
44+
let level_cost = config.level(level.current + level.up).xp_cost;
45+
if xp.relative < level_cost {
46+
break;
47+
}
4848

49-
xp.0 -= xp_cost;
50-
level.up += 1;
49+
xp.relative -= level_cost;
50+
level.up += 1;
51+
}
5152
}
5253
}
5354

54-
fn trigger_level_up(mut level_up_events: EventWriter<LevelUp>, mut level: ResMut<Level>) {
55-
if level.up > 0 {
55+
fn trigger_level_up(
56+
mut level_up_events: EventWriter<LevelUp>,
57+
mut level_query: Query<(Entity, &mut Level)>,
58+
) {
59+
for (entity, mut level) in &mut level_query {
60+
if level.up <= 0 {
61+
continue;
62+
}
63+
5664
level.up -= 1;
5765
level.current += 1;
58-
level_up_events.send(LevelUp);
66+
level_up_events.send(LevelUp(entity));
5967
}
6068
}

src/game/level/xp.rs

+34-20
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,51 @@ use crate::ui::prelude::*;
1111
use crate::util::prelude::*;
1212

1313
pub(super) fn plugin(app: &mut App) {
14-
app.configure::<(Xp, OnReceiveXp, XpReward, IsXpBarFill)>();
14+
app.configure::<(Xp, OnXpReward, XpReward, IsXpBarFill)>();
1515
}
1616

17-
/// The player's XP relative to the current level.
18-
#[derive(Resource, Reflect, Default)]
19-
#[reflect(Resource)]
20-
pub struct Xp(pub f32);
17+
#[derive(Component, Reflect, Default)]
18+
#[reflect(Component)]
19+
pub struct Xp {
20+
/// The total amount of XP.
21+
pub total: f32,
22+
/// The amount of XP relative to the current level.
23+
pub relative: f32,
24+
}
2125

2226
impl Configure for Xp {
2327
fn configure(app: &mut App) {
2428
app.register_type::<Self>();
25-
app.init_resource::<Self>();
2629
}
2730
}
2831

29-
/// An observable event triggered when the player receives XP.
32+
impl Xp {
33+
pub fn gain(&mut self, amount: f32) {
34+
self.total += amount;
35+
self.relative += amount;
36+
}
37+
}
38+
39+
/// An observable event triggered when an entity receives XP.
3040
#[derive(Event)]
31-
pub struct OnReceiveXp(pub f32);
41+
pub struct OnXpReward(pub f32);
3242

33-
impl Configure for OnReceiveXp {
43+
impl Configure for OnXpReward {
3444
fn configure(app: &mut App) {
3545
app.add_event::<Self>();
3646
app.observe(receive_xp);
3747
}
3848
}
3949

40-
fn receive_xp(trigger: Trigger<OnReceiveXp>, mut xp: ResMut<Xp>) {
41-
xp.0 += trigger.event().0;
50+
fn receive_xp(trigger: Trigger<OnXpReward>, mut xp_query: Query<&mut Xp>) {
51+
let entity = r!(trigger.get_entity());
52+
let mut xp = r!(xp_query.get_mut(entity));
53+
xp.gain(trigger.event().0);
4254
}
4355

44-
/// Experience rewarded to the player on death.
56+
// TODO: Not needed for this jam game, but it would be "more correct" to track
57+
// the owner of the projectile that killed the actor with the `XpReward`.
58+
/// Experience rewarded to player entities on death.
4559
#[derive(Component, Reflect, Serialize, Deserialize, Copy, Clone)]
4660
#[reflect(Component)]
4761
#[serde(transparent)]
@@ -69,7 +83,7 @@ fn apply_xp_reward(
6983
let (faction, reward) = r!(death_query.get(entity));
7084

7185
if faction.is_enemy() {
72-
commands.trigger(OnReceiveXp(reward.0));
86+
commands.trigger(OnXpReward(reward.0));
7387
}
7488
}
7589

@@ -86,18 +100,18 @@ impl Configure for IsXpBarFill {
86100

87101
fn update_xp_bar_fill(
88102
config: ConfigRef<LevelConfig>,
89-
level: Res<Level>,
90-
xp: Res<Xp>,
91-
mut xp_bar_fill_query: Query<&mut Style, With<IsXpBarFill>>,
103+
level_query: Query<(&Level, &Xp)>,
104+
mut xp_bar_fill_query: Query<(&mut Style, &Selection), With<IsXpBarFill>>,
92105
) {
93106
let config = r!(config.get());
94107
if config.levels.is_empty() {
95108
return;
96109
}
97-
let xp_cost = config.level(level.current + level.up).xp_cost;
98-
let width = Percent(xp.0 / xp_cost * 100.0);
99110

100-
for mut style in &mut xp_bar_fill_query {
101-
style.width = width;
111+
for (mut style, selection) in &mut xp_bar_fill_query {
112+
let (level, xp) = r!(level_query.get(selection.0));
113+
let level_cost = config.level(level.current + level.up).xp_cost;
114+
115+
style.width = Percent(xp.relative / level_cost * 100.0);
102116
}
103117
}

src/game/wave.rs

+25-24
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ pub struct WaveConfig {
3030
impl Config for WaveConfig {
3131
const PATH: &'static str = "config/wave.ron";
3232
const EXTENSION: &'static str = "wave.ron";
33-
34-
fn on_load(&mut self, _world: &mut World) {}
3533
}
3634

3735
#[derive(Asset, Reflect, Serialize, Deserialize)]
@@ -53,14 +51,13 @@ enum SpawnCondition {
5351
LessThan(usize),
5452
}
5553

56-
#[derive(Resource, Reflect, Default)]
57-
#[reflect(Resource)]
54+
#[derive(Component, Reflect, Default)]
55+
#[reflect(Component)]
5856
struct Wave(usize);
5957

6058
impl Configure for Wave {
6159
fn configure(app: &mut App) {
6260
app.register_type::<Self>();
63-
app.init_resource::<Self>();
6461
app.add_systems(
6562
Update,
6663
Screen::Playing.on_update(
@@ -75,26 +72,29 @@ impl Configure for Wave {
7572
fn spawn_wave_enemies(
7673
mut commands: Commands,
7774
config: ConfigRef<WaveConfig>,
78-
mut wave: ResMut<Wave>,
7975
camera_root: Res<CameraRoot>,
8076
camera_query: Query<&GlobalTransform>,
81-
level: Res<Level>,
77+
mut wave_query: Query<(&mut Wave, &Selection)>,
78+
level_query: Query<&Level>,
8279
) {
8380
let config = r!(config.get());
8481
let camera_gt = r!(camera_query.get(camera_root.primary));
8582
let center = camera_gt.translation().xy();
8683

87-
wave.0 = wave.0.wrapping_add(1);
88-
if wave.0 % config.spawn_cadence != 0 {
89-
return;
90-
}
84+
for (mut wave, selection) in &mut wave_query {
85+
let level = c!(level_query.get(selection.0));
86+
87+
wave.0 = wave.0.wrapping_add(1);
88+
if wave.0 % config.spawn_cadence != 0 {
89+
return;
90+
}
9191

92-
let mut rng = rand::thread_rng();
93-
let spawn_count = (level.current / config.spawn_count_scale)
94-
.max(1)
95-
.min(config.max_spawn_count);
96-
for _ in 0..spawn_count {
97-
let available_actors = config
92+
let mut rng = rand::thread_rng();
93+
let spawn_count = (level.current / config.spawn_count_scale)
94+
.max(1)
95+
.min(config.max_spawn_count);
96+
for _ in 0..spawn_count {
97+
let available_actors = config
9898
.enemies
9999
.iter()
100100
// Flatten each spawn_info with its actor key.
@@ -103,14 +103,15 @@ fn spawn_wave_enemies(
103103
info.condition.is_empty() || any_condition_met(&info.condition, &level.current)
104104
});
105105

106-
if let Some((key, _)) = available_actors.choose(&mut rng) {
107-
let offset =
108-
Annulus::new(config.min_distance, config.max_distance).sample_interior(&mut rng);
109-
let spawn_point = center + offset;
106+
if let Some((key, _)) = available_actors.choose(&mut rng) {
107+
let offset = Annulus::new(config.min_distance, config.max_distance)
108+
.sample_interior(&mut rng);
109+
let spawn_point = center + offset;
110110

111-
commands
112-
.spawn_with(enemy(key))
113-
.insert(Transform::from_translation(spawn_point.extend(0.0)));
111+
commands
112+
.spawn_with(enemy(key))
113+
.insert(Transform::from_translation(spawn_point.extend(0.0)));
114+
}
114115
}
115116
}
116117
}

0 commit comments

Comments
 (0)