|
6 | 6 | //! - When not tired, find the farm field and harvest items over time
|
7 | 7 | //! - When inventory is full, find the market and sell items for money
|
8 | 8 |
|
9 |
| -use bevy::{log::LogPlugin, prelude::*}; |
10 |
| -use bevy_scene_hook::{HookPlugin, HookedSceneBundle, SceneHook}; |
| 9 | +use bevy::scene::SceneInstance; |
| 10 | +use bevy::{color::palettes::css, log::LogPlugin, prelude::*}; |
11 | 11 | use big_brain::prelude::*;
|
12 | 12 | use big_brain_derive::ActionBuilder;
|
13 | 13 |
|
14 |
| -const DEFAULT_COLOR: Color = Color::BLACK; |
15 |
| -const SLEEP_COLOR: Color = Color::RED; |
16 |
| -const FARM_COLOR: Color = Color::BLUE; |
| 14 | +const DEFAULT_COLOR: Color = Color::Srgba(css::BLACK); |
| 15 | +const SLEEP_COLOR: Color = Color::Srgba(css::RED); |
| 16 | +const FARM_COLOR: Color = Color::Srgba(css::BLUE); |
17 | 17 | const MAX_DISTANCE: f32 = 0.1;
|
18 | 18 | const MAX_INVENTORY_ITEMS: f32 = 20.0;
|
19 | 19 | const WORK_NEED_SCORE: f32 = 0.6;
|
@@ -386,8 +386,10 @@ pub fn move_to_nearest_system<T: Component + std::fmt::Debug + Clone>(
|
386 | 386 | let delta_b = *b - actor_transform.translation;
|
387 | 387 | delta_a.length().partial_cmp(&delta_b.length()).unwrap()
|
388 | 388 | })
|
389 |
| - .unwrap() |
390 |
| - .1; |
| 389 | + .and_then(|t| Some(t.1)); |
| 390 | + let Some(goal_transform) = goal_transform else { |
| 391 | + continue; |
| 392 | + }; |
391 | 393 | let delta = goal_transform.translation - actor_transform.translation;
|
392 | 394 | let distance = delta.xz().length();
|
393 | 395 |
|
@@ -498,24 +500,13 @@ fn init_entities(
|
498 | 500 | },
|
499 | 501 | ));
|
500 | 502 |
|
501 |
| - // We use a HookedSceneBundle to attach a SceneHook to the entity. This hook |
502 |
| - // will be called when the entity is spawned, and will allow us to insert |
503 |
| - // additional components into the spawned entities. |
| 503 | + // Loading our scene here. Note we'll still need to add components to different parts |
| 504 | + // of the gltf in order to query their positions. We do this through an observer further below. |
504 | 505 | commands.spawn((
|
505 | 506 | Name::new("Town"),
|
506 |
| - HookedSceneBundle { |
507 |
| - scene: SceneBundle { |
508 |
| - scene: asset_server.load("models/town.glb#Scene0"), |
509 |
| - ..default() |
510 |
| - }, |
511 |
| - hook: SceneHook::new(|entity, cmds| { |
512 |
| - match entity.get::<Name>().map(|t| t.as_str()) { |
513 |
| - Some("Farm_Marker") => cmds.insert(Field), |
514 |
| - Some("Market_Marker") => cmds.insert(Market), |
515 |
| - Some("House_Marker") => cmds.insert(House), |
516 |
| - _ => cmds, |
517 |
| - }; |
518 |
| - }), |
| 507 | + SceneBundle { |
| 508 | + scene: asset_server.load("models/town.glb#Scene0"), |
| 509 | + ..default() |
519 | 510 | },
|
520 | 511 | ));
|
521 | 512 |
|
@@ -601,16 +592,78 @@ fn init_entities(
|
601 | 592 | });
|
602 | 593 | }
|
603 | 594 |
|
| 595 | +// ================================================================================ |
| 596 | +// Scene Loading 🏗️ |
| 597 | +// ================================================================================ |
| 598 | + |
| 599 | +// Define a custom event for our scene loading |
| 600 | +#[derive(Event)] |
| 601 | +struct SceneLoaded { |
| 602 | + /// The entities in this scene |
| 603 | + entities: Vec<Entity>, |
| 604 | +} |
| 605 | + |
| 606 | +// Define a marker component to indicate what entities we've already processed |
| 607 | +#[derive(Component)] |
| 608 | +struct SceneProcessed; |
| 609 | + |
| 610 | +// System to check if a scene has finished loading |
| 611 | +fn check_scene_loaded( |
| 612 | + mut commands: Commands, |
| 613 | + query: Query<(Entity, &SceneInstance), Without<SceneProcessed>>, |
| 614 | + scene_spawner: Res<SceneSpawner>, |
| 615 | +) { |
| 616 | + for (entity, instance) in query.iter() { |
| 617 | + if scene_spawner.instance_is_ready(**instance) { |
| 618 | + commands.entity(entity).insert(SceneProcessed); |
| 619 | + |
| 620 | + let entities = scene_spawner |
| 621 | + .iter_instance_entities(**instance) |
| 622 | + .chain(std::iter::once(entity)); |
| 623 | + |
| 624 | + commands.trigger(SceneLoaded { |
| 625 | + entities: entities.collect(), |
| 626 | + }); |
| 627 | + } |
| 628 | + } |
| 629 | +} |
| 630 | + |
604 | 631 | fn main() {
|
605 | 632 | App::new()
|
606 | 633 | .add_plugins(DefaultPlugins.set(LogPlugin {
|
607 | 634 | level: bevy::log::Level::WARN,
|
608 | 635 | // Use `RUST_LOG=big_brain=trace,farming_sim=trace cargo run --example
|
609 | 636 | // farming_sim --features=trace` to see extra tracing output.
|
610 | 637 | filter: "big_brain=debug,farming_sim=debug".to_string(),
|
611 |
| - update_subscriber: None, |
| 638 | + custom_layer: |_| None, |
612 | 639 | }))
|
613 |
| - .add_plugins(HookPlugin) |
| 640 | + .add_event::<SceneLoaded>() |
| 641 | + .add_systems(Update, check_scene_loaded) |
| 642 | + // This observer will attach components to entities in the scene based on their names. |
| 643 | + .observe( |
| 644 | + |trigger: Trigger<SceneLoaded>, |
| 645 | + query: Query<(Entity, &Name)>, |
| 646 | + mut commands: Commands| { |
| 647 | + for entity in trigger.event().entities.iter() { |
| 648 | + if let Ok((entity, name)) = query.get(*entity) { |
| 649 | + let mut entity_commands = commands.entity(entity); |
| 650 | + |
| 651 | + match name.as_str() { |
| 652 | + "Farm_Marker" => { |
| 653 | + entity_commands.insert(Field); |
| 654 | + } |
| 655 | + "Market_Marker" => { |
| 656 | + entity_commands.insert(Market); |
| 657 | + } |
| 658 | + "House_Marker" => { |
| 659 | + entity_commands.insert(House); |
| 660 | + } |
| 661 | + _ => (), |
| 662 | + } |
| 663 | + } |
| 664 | + } |
| 665 | + }, |
| 666 | + ) |
614 | 667 | .add_plugins(BigBrainPlugin::new(PreUpdate))
|
615 | 668 | .add_systems(Startup, init_entities)
|
616 | 669 | .add_systems(Update, (fatigue_system, update_ui))
|
|
0 commit comments