From 03251c711975d47ac81233e8f9d585b115871d6b Mon Sep 17 00:00:00 2001 From: Wabtey Date: Sat, 16 Sep 2023 16:20:16 +0200 Subject: [PATCH 1/8] rename `PlayerLocation` to `Location` - The component `Location` is given to - Each npc - Each landmark - `Location` is still a `State` to keep the quick and easy access to the player's location --- src/constants.rs | 57 ++++++++++++++++++++--------- src/debug.rs | 10 +++-- src/locations/landmarks.rs | 39 ++++++++++---------- src/locations/temple/hall.rs | 8 ++-- src/locations/temple/main_room.rs | 14 +++---- src/locations/temple/mod.rs | 41 ++++++++++----------- src/locations/temple/secret_room.rs | 10 ++--- 7 files changed, 101 insertions(+), 78 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index bd9a0f9..e86b9fe 100755 --- a/src/constants.rs +++ b/src/constants.rs @@ -365,12 +365,19 @@ pub mod locations { (68.5 * TILE_SIZE, 63.5 * TILE_SIZE, WILL_BE_COMPUTE_LATER), // RightRight ]; - // pub const STATUE_SWITCH_Z_OFFSET: f32 = 0.; - // FIXME: Why the Y of cat/fabien statue are different ?? - pub const CAT_STATUE_POSITION: (f32, f32, f32) = - (-100. * TILE_SIZE, 75. * TILE_SIZE, WILL_BE_COMPUTE_LATER); - pub const FABIEN_STATUE_POSITION: (f32, f32, f32) = - (52. * TILE_SIZE, 77. * TILE_SIZE, WILL_BE_COMPUTE_LATER); + pub const STATUE_Y: f32 = 75.; + pub const CAT_STATUE_X: f32 = -100.; + pub const CAT_STATUE_POSITION: (f32, f32, f32) = ( + CAT_STATUE_X * TILE_SIZE, + STATUE_Y * TILE_SIZE, + WILL_BE_COMPUTE_LATER, + ); + pub const FABIEN_STATUE_X: f32 = 52.; + pub const FABIEN_STATUE_POSITION: (f32, f32, f32) = ( + FABIEN_STATUE_X * TILE_SIZE, + STATUE_Y * TILE_SIZE, + WILL_BE_COMPUTE_LATER, + ); pub const BANNER_INTERACTION_ID: u32 = 3; pub const BANNER_INTERACT_BUTTON_POSITION: (f32, f32, f32) = @@ -384,19 +391,35 @@ pub mod locations { // use super::*; use crate::constants::TILE_SIZE; - pub const LANDMARK_CAT_STATUE_LEFT: (f32, f32, f32) = - (-110. * TILE_SIZE, 70. * TILE_SIZE, 0.); - pub const LANDMARK_CAT_STATUE_MIDDLE: (f32, f32, f32) = - (-100. * TILE_SIZE, 65. * TILE_SIZE, 0.); - pub const LANDMARK_CAT_STATUE_RIGHT: (f32, f32, f32) = - (-90. * TILE_SIZE, 70. * TILE_SIZE, 0.); + use super::{CAT_STATUE_X, FABIEN_STATUE_X, STATUE_Y}; - pub const LANDMARK_FABIEN_STATUE_LEFT: (f32, f32, f32) = - (-42. * TILE_SIZE, 70. * TILE_SIZE, 0.); + pub const LANDMARK_SENSOR_SIZE: f32 = 2.5; + + pub const LANDMARK_CAT_STATUE_LEFT: (f32, f32, f32) = ( + CAT_STATUE_X - 10. * TILE_SIZE, + STATUE_Y - 25. * TILE_SIZE, + 0., + ); + pub const LANDMARK_CAT_STATUE_MIDDLE: (f32, f32, f32) = + (CAT_STATUE_X * TILE_SIZE, STATUE_Y - 35. * TILE_SIZE, 0.); + pub const LANDMARK_CAT_STATUE_RIGHT: (f32, f32, f32) = ( + CAT_STATUE_X + 10. * TILE_SIZE, + STATUE_Y - 25. * TILE_SIZE, + 0., + ); + + pub const LANDMARK_FABIEN_STATUE_LEFT: (f32, f32, f32) = ( + FABIEN_STATUE_X - 10. * TILE_SIZE, + STATUE_Y - 25. * TILE_SIZE, + 0., + ); pub const LANDMARK_FABIEN_STATUE_MIDDLE: (f32, f32, f32) = - (-52. * TILE_SIZE, 65. * TILE_SIZE, 0.); - pub const LANDMARK_FABIEN_STATUE_RIGHT: (f32, f32, f32) = - (-62. * TILE_SIZE, 70. * TILE_SIZE, 0.); + (FABIEN_STATUE_X * TILE_SIZE, STATUE_Y - 35. * TILE_SIZE, 0.); + pub const LANDMARK_FABIEN_STATUE_RIGHT: (f32, f32, f32) = ( + FABIEN_STATUE_X + 10. * TILE_SIZE, + STATUE_Y - 25. * TILE_SIZE, + 0., + ); } } diff --git a/src/debug.rs b/src/debug.rs index df60667..8493913 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -7,7 +7,10 @@ use crate::{ }, characters::npcs::movement::{Chaser, NPCBehavior, TargetSeeker, TargetType}, collisions::{TesselatedCollider, TesselatedColliderConfig}, - locations::temple::{OverlappingEntity, PlayerLocation}, + locations::{ + landmarks::Landmark, + temple::{Location, OverlappingEntity}, + }, menu::{ManorLightsPattern, ManorLightsTimer}, GameState, }; @@ -19,10 +22,10 @@ impl Plugin for DebugPlugin { if cfg!(debug_assertions) { app.add_plugins((WorldInspectorPlugin::new(),)) .register_type::() - .register_type::() + .register_type::() .add_plugins(( StateInspectorPlugin::::default(), - StateInspectorPlugin::::default(), + StateInspectorPlugin::::default(), )) /* -------------------------------------------------------------------------- */ /* Global Animation */ @@ -47,6 +50,7 @@ impl Plugin for DebugPlugin { /* Map */ /* -------------------------------------------------------------------------- */ .register_type::() + .register_type::() /* -------------------------------------------------------------------------- */ /* Hitbox */ /* -------------------------------------------------------------------------- */ diff --git a/src/locations/landmarks.rs b/src/locations/landmarks.rs index 2c71c11..3cb204e 100755 --- a/src/locations/landmarks.rs +++ b/src/locations/landmarks.rs @@ -19,7 +19,7 @@ use crate::{ constants::{character::npcs::movement::REST_TIMER, locations::main_room::landmarks::*}, }; -use super::temple::PlayerLocation; +use super::temple::Location; pub struct LandmarkPlugin; @@ -38,7 +38,7 @@ impl Plugin for LandmarkPlugin { /// to occupy one of the free landmark. /// The npc will reserved the landmark, only the player can occupy a reserved landmark. /// A occupied landmark can only be freed by the occupant. -#[derive(PartialEq, Eq, Default, Component)] +#[derive(PartialEq, Eq, Debug, Reflect, Default, Component)] pub enum LandmarkStatus { #[default] Free, @@ -47,15 +47,15 @@ pub enum LandmarkStatus { } /// TEMP: if there is only the field `status` just use the enum instead. -#[derive(Component)] +#[derive(Reflect, Debug, Component)] pub struct Landmark { pub status: LandmarkStatus, /// DOC: ambiguous name - pub location: PlayerLocation, + pub location: Location, } impl Landmark { - pub fn new(landmark_location: PlayerLocation) -> Self { + pub fn new(landmark_location: Location) -> Self { Landmark { status: LandmarkStatus::default(), location: landmark_location, @@ -65,7 +65,7 @@ impl Landmark { #[derive(Debug)] pub enum LandmarkReservationError { - EmptyQuery, + NoFreeLandmarks, } /// TODO: Create an impl to automatictly Reserved a free landmark @@ -79,8 +79,7 @@ pub fn reserved_random_free_landmark( .filter(|(_, landmark)| landmark.status == LandmarkStatus::Free) .choose(&mut rand::thread_rng()) { - // create custom error - None => Err(LandmarkReservationError::EmptyQuery), + None => Err(LandmarkReservationError::NoFreeLandmarks), Some((free_random_landmark, mut landmark)) => { landmark.status = LandmarkStatus::Reserved; Ok(free_random_landmark) @@ -183,29 +182,29 @@ fn spawn_landmarks(mut commands: Commands) { )) .with_children(|parent| { parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_LEFT.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Cat Statue Left"), )); parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_MIDDLE.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Cat Statue Middle"), )); parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_RIGHT.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Cat Statue Right"), )); @@ -218,29 +217,29 @@ fn spawn_landmarks(mut commands: Commands) { )) .with_children(|parent| { parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_LEFT.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Fabien Statue Left"), )); parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_MIDDLE.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Fabien Statue Middle"), )); parent.spawn(( - Landmark::new(PlayerLocation::Temple), + Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_RIGHT.into(), )), - Collider::ball(5.), + Collider::ball(LANDMARK_SENSOR_SIZE), Sensor, Name::new("Landmark Fabien Statue Right"), )); diff --git a/src/locations/temple/hall.rs b/src/locations/temple/hall.rs index 801f84e..f54cc8d 100644 --- a/src/locations/temple/hall.rs +++ b/src/locations/temple/hall.rs @@ -16,8 +16,8 @@ use crate::{ }, interactions::{Interactible, InteractionSensor}, locations::temple::{ - Chandelier, DoorColliderClosed, DoorState, Flame, LocationSensor, OverlappingEntity, - PlayerLocation, WallCollider, + Chandelier, DoorColliderClosed, DoorState, Flame, Location, LocationSensor, + OverlappingEntity, WallCollider, }, }; @@ -262,7 +262,7 @@ pub fn setup_hall( ActiveEvents::COLLISION_EVENTS, Sensor, LocationSensor { - location: PlayerLocation::Hall, + location: Location::Hall, }, Name::new("Hall Sensor from Temple"), )); @@ -296,7 +296,7 @@ pub fn setup_hall( }, }, Transform::default(), - WallCollider(PlayerLocation::Hall), + WallCollider(Location::Hall), )); } }); diff --git a/src/locations/temple/main_room.rs b/src/locations/temple/main_room.rs index d3df019..b84be00 100644 --- a/src/locations/temple/main_room.rs +++ b/src/locations/temple/main_room.rs @@ -9,8 +9,8 @@ use crate::{ interactions::{Interactible, InteractionSensor}, locations::temple::{ secret_room::{AddSecretRoomCoverEvent, RemoveSecretRoomCoverEvent}, - Chandelier, DoorColliderClosed, DoorState, Flame, LocationSensor, OverlappingEntity, - PlayerLocation, WallCollider, + Chandelier, DoorColliderClosed, DoorState, Flame, Location, LocationSensor, + OverlappingEntity, WallCollider, }, }; @@ -44,13 +44,13 @@ pub struct SecretBannerEvent(pub DoorState); /// REFACTOR: SecretRoomCover pub fn secret_banner_interaction( mut secret_banner_event: EventReader, - player_location: Res>, + player_location: Res>, mut remove_secret_room_cover_event: EventWriter, mut add_secret_room_cover_event: EventWriter, ) { for SecretBannerEvent(door_state) in secret_banner_event.iter() { - if player_location.get() == &PlayerLocation::Temple { + if player_location.get() == &Location::Temple { match *door_state { DoorState::Closed => { remove_secret_room_cover_event.send(RemoveSecretRoomCoverEvent) @@ -181,7 +181,7 @@ pub fn setup_main_room( ActiveEvents::COLLISION_EVENTS, Sensor, LocationSensor { - location: PlayerLocation::Temple, + location: Location::Temple, }, Name::new("Temple Sensor from Hall"), )); @@ -192,7 +192,7 @@ pub fn setup_main_room( ActiveEvents::COLLISION_EVENTS, Sensor, LocationSensor { - location: PlayerLocation::Temple, + location: Location::Temple, }, Name::new("Temple Sensor from Secret Room"), )); @@ -214,7 +214,7 @@ pub fn setup_main_room( }, }, Transform::default(), - WallCollider(PlayerLocation::Temple), + WallCollider(Location::Temple), )); } }); diff --git a/src/locations/temple/mod.rs b/src/locations/temple/mod.rs index a2fb663..bed2dd8 100644 --- a/src/locations/temple/mod.rs +++ b/src/locations/temple/mod.rs @@ -19,8 +19,8 @@ pub mod secret_room; #[derive(Component, Deref, DerefMut)] pub struct ZPosition(f32); -#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, Reflect, States)] -pub enum PlayerLocation { +#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, Reflect, Component, States)] +pub enum Location { #[default] Hall, Temple, @@ -31,7 +31,7 @@ pub struct TemplePlugin; impl Plugin for TemplePlugin { fn build(&self, app: &mut App) { - app.add_state::() + app.add_state::() .add_event::() .add_event::() .add_event::() @@ -70,15 +70,15 @@ impl Plugin for TemplePlugin { main_room::secret_banner_interaction.run_if(in_temple_or_secret_room), ) .add_systems( - OnEnter(PlayerLocation::Hall), + OnEnter(Location::Hall), control_wall_collider.run_if(playing), ) .add_systems( - OnEnter(PlayerLocation::Temple), + OnEnter(Location::Temple), control_wall_collider.run_if(playing), ) .add_systems( - OnEnter(PlayerLocation::SecretRoom), + OnEnter(Location::SecretRoom), control_wall_collider.run_if(playing), ); } @@ -88,26 +88,23 @@ impl Plugin for TemplePlugin { /* Run If Systems */ /* -------------------------------------------------------------------------- */ -fn in_hall(location: Res>, game_state: Res>) -> bool { - location.get() == &PlayerLocation::Hall && game_state.get() == &GameState::Playing +fn in_hall(location: Res>, game_state: Res>) -> bool { + location.get() == &Location::Hall && game_state.get() == &GameState::Playing } -fn _in_temple(location: Res>, game_state: Res>) -> bool { - location.get() == &PlayerLocation::Temple && game_state.get() == &GameState::Playing +fn _in_temple(location: Res>, game_state: Res>) -> bool { + location.get() == &Location::Temple && game_state.get() == &GameState::Playing } -fn _in_secret_room( - location: Res>, - game_state: Res>, -) -> bool { - location.get() == &PlayerLocation::SecretRoom && game_state.get() == &GameState::Playing +fn _in_secret_room(location: Res>, game_state: Res>) -> bool { + location.get() == &Location::SecretRoom && game_state.get() == &GameState::Playing } fn in_temple_or_secret_room( - location: Res>, + location: Res>, game_state: Res>, ) -> bool { - (location.get() == &PlayerLocation::SecretRoom || location.get() == &PlayerLocation::Temple) + (location.get() == &Location::SecretRoom || location.get() == &Location::Temple) && game_state.get() == &GameState::Playing } @@ -133,11 +130,11 @@ pub struct Chandelier; pub struct Flame; #[derive(Component)] -pub struct WallCollider(pub PlayerLocation); +pub struct WallCollider(pub Location); #[derive(Component)] pub struct LocationSensor { - pub location: PlayerLocation, + pub location: Location, } /// TODO: make it work @@ -200,8 +197,8 @@ pub fn location_event( location_sensor_query: Query<(Entity, &LocationSensor)>, character_hitbox_query: Query<(Entity, &Parent), With>, - location: Res>, - mut next_location: ResMut>, + location: Res>, + mut next_location: ResMut>, ) { for collision_event in collision_events.iter() { match collision_event { @@ -244,7 +241,7 @@ pub fn location_event( /// NOTE: Instead of OnEnter(...), just check if the state has changed fn control_wall_collider( mut commands: Commands, - player_location: Res>, + player_location: Res>, wall_colliders_query: Query<(Entity, &WallCollider)>, ) { let current_location = player_location.get(); diff --git a/src/locations/temple/secret_room.rs b/src/locations/temple/secret_room.rs index 3a07529..45d887e 100644 --- a/src/locations/temple/secret_room.rs +++ b/src/locations/temple/secret_room.rs @@ -9,7 +9,7 @@ use crate::{ }, collisions::{TesselatedCollider, TesselatedColliderConfig}, constants::{locations::secret_room::*, BACKGROUND_COLOR_INGAME}, - locations::temple::{LocationSensor, OverlappingEntity, PlayerLocation, WallCollider}, + locations::temple::{Location, LocationSensor, OverlappingEntity, WallCollider}, }; /* -------------------------------------------------------------------------- */ @@ -97,13 +97,13 @@ pub fn add_secret_room_cover( /// OPTIMIZE: OnEnter of secretRoom => visibility on, OnExit => off pub fn second_layer_fake_wall_visibility( - location: Res>, + location: Res>, mut second_layer_fake_wall_query: Query<&mut Visibility, With>, ) { if location.is_changed() { let mut visibility = second_layer_fake_wall_query.single_mut(); *visibility = match location.get() { - PlayerLocation::SecretRoom => Visibility::Inherited, + Location::SecretRoom => Visibility::Inherited, _ => Visibility::Hidden, }; } @@ -291,7 +291,7 @@ pub fn setup_secret_room( ActiveEvents::COLLISION_EVENTS, Sensor, LocationSensor { - location: PlayerLocation::SecretRoom, + location: Location::SecretRoom, }, Name::new("Secret Sensor from Temple"), )); @@ -313,7 +313,7 @@ pub fn setup_secret_room( }, }, Transform::default(), - WallCollider(PlayerLocation::SecretRoom), + WallCollider(Location::SecretRoom), )); } }); From 4cb2c5ecd729aa88fe66c0a5280665023a225aac Mon Sep 17 00:00:00 2001 From: Wabtey Date: Sat, 16 Sep 2023 16:22:18 +0200 Subject: [PATCH 2/8] add updates to the `CHANGELOG` --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a53e9e..5079c27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Dialog Update - [v0.4.0](https://github.com/Fabinistere/fabien-et-la-trahison-de-olf/releases/tag/v0.4.0) - 2023-09-04 +### Changed + +- globalize `PlayerLocation` to `Location` + - The component `Location` is given to + - Each npc + - Each landmark + - `Location` is still a `State` to keep the quick and easy access to the player's location + +### Dialog + +- YML Dialog and reorganize ui components + +### NPCs' Behavior + +#### Refactored + +- Follow Behavior + - add and use a `FollowRangeSensor` to detect the follow_target's hitbox + +#### Added + +- Detection Behavior + - `TargetSeeker` + - `DetectionRangeSensor` used to analyze all entering characters' hitbox and compare with their `TargetType` + - if it correpond: Deactivate this sensor and start the Chase Behavior with the component `Chaser`. +- Chase Behavior + - `Chaser` + - `PursuitRangeSensor` used to analyze all exiting characters' hitbox and compare with their `Chaser`'s `target` + - if it correpond: Deactivate this sensor and remove the Chase Behavior. + - The `CharacterCloseSensor` used to detect all entering `Chaser`s hitbox and start a Combat if the `Chaser`'s `target` is the parent of the `CharacterCloseSensor`. + ## Map, Title Screen and Animation Update - [v0.3.9](https://github.com/Fabinistere/fabien-et-la-trahison-de-olf/releases/tag/v0.3.9) - 2023-08-31 [![v0.3.9](https://img.shields.io/badge/v0.3.9-gray?style=flat&logo=github&logoColor=181717&link=https://github.com/Fabinistere/fabien-et-la-trahison-de-olf/releases/tag/v0.3.9)](https://github.com/Fabinistere/fabien-et-la-trahison-de-olf/releases/tag/v0.3.9) From 35bb266629cf7854795069c0c9445843ae42f526 Mon Sep 17 00:00:00 2001 From: Wabtey Date: Mon, 18 Sep 2023 16:49:03 +0200 Subject: [PATCH 3/8] refactor Landmark occupation, globalize Spritesheet Indice - globalize Animation Indices for Character SpriteSheet - Landmark occupation - Landmark location - limite to their zone the npc reservation - Spawn a lot more landmarks --- src/animations/mod.rs | 39 +++++++- src/characters/npcs/mod.rs | 51 +--------- src/characters/npcs/movement.rs | 66 +++--------- src/constants.rs | 1 + src/locations/landmarks.rs | 150 ++++++++++++++++------------ src/locations/temple/mod.rs | 2 +- src/locations/temple/secret_room.rs | 1 + 7 files changed, 145 insertions(+), 165 deletions(-) mode change 100644 => 100755 src/animations/mod.rs mode change 100644 => 100755 src/locations/temple/mod.rs diff --git a/src/animations/mod.rs b/src/animations/mod.rs old mode 100644 new mode 100755 index 6bea73a..5944442 --- a/src/animations/mod.rs +++ b/src/animations/mod.rs @@ -7,7 +7,15 @@ use bevy::prelude::*; pub use fade::{Fade, FadeType}; pub use slide::{Slide, UiSlide, UiSlideType}; -use crate::in_menu; +use crate::{ + constants::character::{ + COLUMN_FRAME_IDLE_END, COLUMN_FRAME_IDLE_START, COLUMN_FRAME_RUN_END, + SPRITESHEET_COLUMN_NUMBER, SPRITESHEET_LINE_NUMBER, + }, + in_menu, +}; + +use self::sprite_sheet_animation::CharacterState; // DOC: create systemsLabel for `sprite_sheet_animation::tempo_animation_timer` @@ -16,6 +24,7 @@ pub struct AnimationPlugin; impl Plugin for AnimationPlugin { fn build(&self, app: &mut App) { app.init_resource::() + .init_resource::() .add_systems( PostUpdate, ( @@ -68,3 +77,31 @@ impl FromWorld for CharacterSpriteSheet { } } } + +#[derive(Deref, Clone, Resource)] +pub struct GlobalAnimationIndices(Vec>); + +impl FromWorld for GlobalAnimationIndices { + fn from_world(_world: &mut World) -> Self { + let mut global_animations_indices: Vec> = Vec::new(); + for line in 0..SPRITESHEET_LINE_NUMBER { + global_animations_indices.push(vec![ + // Run Indexes for each line + ( + line * SPRITESHEET_COLUMN_NUMBER, + line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_RUN_END, + CharacterState::Idle, + // CharacterState::Run, ? + ), + // Idle Indexes for each line + ( + line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_START, + line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_END, + CharacterState::Idle, + ), + ]); + } + + GlobalAnimationIndices(global_animations_indices) + } +} diff --git a/src/characters/npcs/mod.rs b/src/characters/npcs/mod.rs index d962a26..0ad0d86 100755 --- a/src/characters/npcs/mod.rs +++ b/src/characters/npcs/mod.rs @@ -12,16 +12,13 @@ use yml_dialog::DialogNode; use crate::{ animations::{ sprite_sheet_animation::{AnimationIndices, CharacterState}, - CharacterSpriteSheet, + CharacterSpriteSheet, GlobalAnimationIndices, }, characters::{movement::MovementBundle, npcs::movement::NPCBehavior, CharacterHitbox}, combat::Reputation, constants::character::{npcs::*, player::PLAYER_SPAWN, *}, interactions::{Interactible, InteractionSensor}, - locations::{ - landmarks::{reserved_random_free_landmark, Landmark, LandmarkStatus}, - temple::OverlappingEntity, - }, + locations::temple::OverlappingEntity, ui::dialog_systems::{CurrentInterlocutor, DialogMap}, GameState, HUDState, }; @@ -31,8 +28,6 @@ use self::{ movement::{FollowRangeSensor, TargetSeeker, TargetType}, }; -use super::movement::CharacterCloseSensor; - #[derive(Default)] pub struct NPCPlugin; @@ -145,27 +140,9 @@ fn spawn_characters( mut commands: Commands, characters_spritesheet: Res, mut dialogs: ResMut, - mut landmark_sensor_query: Query<(Entity, &mut Landmark), With>, + global_animations_indices: Res, + // mut landmark_sensor_query: Query<(Entity, &mut Landmark), With>, ) { - let mut global_animations_indices: Vec> = Vec::new(); - for line in 0..16 { - global_animations_indices.push(vec![ - // Run Indexes for each line - ( - line * SPRITESHEET_COLUMN_NUMBER, - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_RUN_END, - CharacterState::Idle, - // CharacterState::Run, ? - ), - // Idle Indexes for each line - ( - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_START, - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_END, - CharacterState::Idle, - ), - ]); - } - /* -------------------------------------------------------------------------- */ /* Olf Cat */ /* -------------------------------------------------------------------------- */ @@ -365,27 +342,9 @@ fn spawn_vilains( mut commands: Commands, characters_spritesheet: Res, mut dialogs: ResMut, + global_animations_indices: Res, // mut landmark_sensor_query: Query<(Entity, &mut Landmark), With>, ) { - let mut global_animations_indices: Vec> = Vec::new(); - for line in 0..16 { - global_animations_indices.push(vec![ - // Run Indexes for each line - ( - line * SPRITESHEET_COLUMN_NUMBER, - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_RUN_END, - CharacterState::Idle, - // CharacterState::Run, ? - ), - // Idle Indexes for each line - ( - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_START, - line * SPRITESHEET_COLUMN_NUMBER + COLUMN_FRAME_IDLE_END, - CharacterState::Idle, - ), - ]); - } - /* -------------------------------------------------------------------------- */ /* Vilains */ /* -------------------------------------------------------------------------- */ diff --git a/src/characters/npcs/movement.rs b/src/characters/npcs/movement.rs index 3c617de..c920f49 100755 --- a/src/characters/npcs/movement.rs +++ b/src/characters/npcs/movement.rs @@ -25,7 +25,10 @@ use crate::{ collisions::CollisionEventExt, combat::{CombatEvent, FairPlayTimer, Reputation}, constants::TILE_SIZE, - locations::landmarks::{reserved_random_free_landmark, Landmark, LandmarkStatus}, + locations::{ + landmarks::{reserved_random_free_landmark, Landmark, LandmarkStatus}, + temple::Location, + }, }; // pub const PROXIMITY_RADIUS: f32 = 64.; @@ -38,7 +41,7 @@ use crate::{ pub enum NPCBehavior { /// The entity runs to a specify location and occupy this zone. /// Tourist butterfly. - LandmarkSeeking(Entity), + LandmarkSeeking(Entity, Location), Camping, Follow { target: Entity, @@ -226,15 +229,16 @@ pub fn npc_movement( let (vel_x, vel_y) = match potential_chaser { None => match *behavior { NPCBehavior::Camping => (0., 0.), - NPCBehavior::LandmarkSeeking(destination) => { + NPCBehavior::LandmarkSeeking(destination, location) => { let (_, landmark) = landmark_sensor_query.get(destination).unwrap(); let landmark_transform = pos_query.get(destination).unwrap(); match landmark.status { - LandmarkStatus::Occupied => { + LandmarkStatus::OccupiedBy(_) => { // FIXME: Match the LandmarkReservationError let next_destination = - reserved_random_free_landmark(&mut landmark_sensor_query).unwrap(); - *behavior = NPCBehavior::LandmarkSeeking(next_destination); + reserved_random_free_landmark(&mut landmark_sensor_query, location) + .unwrap(); + *behavior = NPCBehavior::LandmarkSeeking(next_destination, location); let next_transform = pos_query.get(next_destination).unwrap(); move_to(next_transform, transform, speed) } @@ -320,8 +324,8 @@ pub fn chase_management( mut ev_stop_chase: EventWriter, ) { for collision_event in collision_events.iter() { - let entity_1 = collision_event.entities().0; - let entity_2 = collision_event.entities().1; + // info!("{:#?}", collision_event); + let (entity_1, entity_2) = collision_event.entities(); // if rapier_context.intersection_pair(entity_1, entity_2) == Some(true) { // info!("Some(true) with {:#?}, {:#?}", entity_1, entity_2); @@ -519,52 +523,6 @@ fn move_to(target_transform: &GlobalTransform, transform: &Transform, speed: &Sp (vel_x, vel_y) } -/// Give velocity x and y value to move forward a certain vec3 -fn move_to_dest(target_vec3: Vec3, transform: &Transform, speed: &Speed) -> (f32, f32) { - let up = target_vec3.y > transform.translation.y; - let down = target_vec3.y < transform.translation.y; - let left = target_vec3.x < transform.translation.x; - let right = target_vec3.x > transform.translation.x; - - let x_axis = -(left as i8) + right as i8; - let y_axis = -(down as i8) + up as i8; - - // println!("x: {}, y: {}", x_axis, y_axis); - - let mut vel_x = x_axis as f32 * **speed; - let mut vel_y = y_axis as f32 * **speed; - - if x_axis != 0 && y_axis != 0 { - vel_x *= (std::f32::consts::PI / 4.).cos(); - vel_y *= (std::f32::consts::PI / 4.).cos(); - } - - (vel_x, vel_y) -} - -/// # Parameters -/// -/// position: of a entity -/// direction: the middle of the future zone, -/// is on the middle of the segment [a,c] -/// -/// # Return -/// returns true if the entity is on the square around the direction point -/// -/// # Note -/// -/// XXX: Rework this Approximation Louche -fn close(position: Vec3, direction: Vec3, range: f32) -> bool { - // direction.x == position.x && - // direction.y == position.y - - let a = Vec3::new(direction.x - range, direction.y + range, direction.z); - - let c = Vec3::new(direction.x + range, direction.y - range, direction.z); - - position.x >= a.x && position.x <= c.x && position.y <= a.y && position.y >= c.y -} - /** * param: * force diff --git a/src/constants.rs b/src/constants.rs index e86b9fe..c671c06 100755 --- a/src/constants.rs +++ b/src/constants.rs @@ -90,6 +90,7 @@ pub mod character { pub const COLUMN_FRAME_IDLE_START: usize = 4; pub const COLUMN_FRAME_IDLE_END: usize = 5; + pub const SPRITESHEET_LINE_NUMBER: usize = 16; pub const SPRITESHEET_COLUMN_NUMBER: usize = 6; pub mod player { diff --git a/src/locations/landmarks.rs b/src/locations/landmarks.rs index 3cb204e..99bbaaf 100755 --- a/src/locations/landmarks.rs +++ b/src/locations/landmarks.rs @@ -4,8 +4,7 @@ //! For example, it could be the throne side, statue admiration, etc. use bevy::prelude::*; -use bevy_ecs::query::{ReadOnlyWorldQuery, WorldQuery}; -use bevy_rapier2d::prelude::{Collider, CollisionEvent, Sensor}; +use bevy_rapier2d::prelude::{ActiveEvents, Collider, CollisionEvent, Sensor}; use rand::seq::IteratorRandom; use std::time::Duration; @@ -43,14 +42,13 @@ pub enum LandmarkStatus { #[default] Free, Reserved, - Occupied, + OccupiedBy(Entity), } /// TEMP: if there is only the field `status` just use the enum instead. #[derive(Reflect, Debug, Component)] pub struct Landmark { pub status: LandmarkStatus, - /// DOC: ambiguous name pub location: Location, } @@ -73,10 +71,13 @@ pub enum LandmarkReservationError { /// LandmarkReservationError pub fn reserved_random_free_landmark( landmark_sensor_query: &mut Query<(Entity, &mut Landmark), With>, + location: Location, ) -> Result { match (*landmark_sensor_query) .iter_mut() - .filter(|(_, landmark)| landmark.status == LandmarkStatus::Free) + .filter(|(_, landmark)| { + landmark.status == LandmarkStatus::Free && landmark.location == location + }) .choose(&mut rand::thread_rng()) { None => Err(LandmarkReservationError::NoFreeLandmarks), @@ -99,69 +100,91 @@ fn landmark_arrival( mut commands: Commands, character_hitbox_query: Query<(Entity, &Parent, &Name), With>, - mut npc_query: Query<(&mut NPCBehavior, &Name), With>, + mut npc_query: Query<(Entity, &mut NPCBehavior, &Name), With>, player_query: Query>, mut landmark_sensor_query: Query<(Entity, &mut Landmark), With>, // parent_query: Query<&Parent>, ) { for collision_event in collision_events.iter() { - let entity_1 = collision_event.entities().0; - let entity_2 = collision_event.entities().1; + // info!("{:#?}", collision_event); + let (entity_1, entity_2) = collision_event.entities(); - match ( + if let (Err(_), Ok((character_hitbox, character_parent, name))) + | (Ok((character_hitbox, character_parent, name)), Err(_)) = ( character_hitbox_query.get(entity_1), character_hitbox_query.get(entity_2), ) { - (Err(_), Ok((character_hitbox, character_parent, name))) - | (Ok((character_hitbox, character_parent, name)), Err(_)) => { - let potential_landmark = if character_hitbox == entity_1 { - entity_2 - } else { - entity_1 - }; - if let Ok((landmark_entity, mut landmark)) = - landmark_sensor_query.get_mut(potential_landmark) - { - if let Ok((mut behavior, _npc_name)) = npc_query.get_mut(**character_parent) { - if let NPCBehavior::LandmarkSeeking(landmark_destination) = *behavior { - if landmark_destination == landmark_entity { - match landmark.status { - LandmarkStatus::Occupied => { - // send an event to redirect the npc - warn!("This landmark {:?} was claimed before the NPC {:?} arrived", landmark_entity, **character_parent) - } - _ => { - landmark.status = LandmarkStatus::Occupied; - // TODO: Or start dialog with the other - info!(target: "Start Rest", "{:?}, {}", **character_parent, name); - commands.entity(**character_parent).insert(RestTime { - timer: Timer::new( - Duration::from_secs(REST_TIMER), - TimerMode::Once, - ), - }); - let next_destination = reserved_random_free_landmark( - &mut landmark_sensor_query, - ) - .unwrap(); - - *behavior = NPCBehavior::LandmarkSeeking(next_destination); - } + let potential_landmark = if character_hitbox == entity_1 { + entity_2 + } else { + entity_1 + }; + if let Ok((landmark_entity, mut landmark)) = + landmark_sensor_query.get_mut(potential_landmark) + { + if let Ok((npc, mut behavior, _npc_name)) = npc_query.get_mut(**character_parent) { + if let NPCBehavior::LandmarkSeeking(landmark_destination, location) = *behavior + { + // A npc enters/exits a landmark sensor + match landmark.status { + LandmarkStatus::OccupiedBy(occupant) => { + if collision_event.is_started() + && landmark_destination == landmark_entity + { + // info!("This landmark {:?} was claimed before the NPC {:?} arrived", landmark_entity, **character_parent) + let next_destination = reserved_random_free_landmark( + &mut landmark_sensor_query, + location, + ) + .unwrap(); + *behavior = + NPCBehavior::LandmarkSeeking(next_destination, location); + } else if collision_event.is_stopped() && occupant == npc { + landmark.status = LandmarkStatus::Free; + } + } + _ => { + if collision_event.is_started() + && landmark_destination == landmark_entity + { + landmark.status = LandmarkStatus::OccupiedBy(npc); + // TODO: Or start dialog with the other + info!(target: "Start Rest", "{:?}, {}", **character_parent, name); + commands.entity(**character_parent).insert(RestTime { + timer: Timer::new( + Duration::from_secs(REST_TIMER), + TimerMode::Once, + ), + }); + let next_destination = reserved_random_free_landmark( + &mut landmark_sensor_query, + location, + ) + .unwrap(); + + *behavior = + NPCBehavior::LandmarkSeeking(next_destination, location); } } } - } else if player_query.get(**character_parent).is_ok() { - match landmark.status { - LandmarkStatus::Occupied => {} - LandmarkStatus::Free | LandmarkStatus::Reserved => { - landmark.status = LandmarkStatus::Occupied + } + } else if player_query.get(**character_parent).is_ok() { + // The player enters/exits a landmark + match landmark.status { + LandmarkStatus::OccupiedBy(occupant) => { + if collision_event.is_stopped() && occupant == **character_parent { + landmark.status = LandmarkStatus::Free; + } + } + LandmarkStatus::Free | LandmarkStatus::Reserved => { + if collision_event.is_started() { + landmark.status = LandmarkStatus::OccupiedBy(**character_parent) } } } } } - _ => {} } } } @@ -172,8 +195,14 @@ fn landmark_arrival( fn spawn_landmarks(mut commands: Commands) { commands - .spawn(TransformBundle::default()) + .spawn((TransformBundle::default(), Name::new("Landmarks"))) .with_children(|parent| { + let landmark_sensor = ( + Collider::ball(LANDMARK_SENSOR_SIZE), + ActiveEvents::COLLISION_EVENTS, + Sensor, + ); + parent .spawn(( LandmarkGroup, @@ -186,17 +215,15 @@ fn spawn_landmarks(mut commands: Commands) { TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_LEFT.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, Name::new("Landmark Cat Statue Left"), + landmark_sensor.clone(), )); parent.spawn(( Landmark::new(Location::Temple), TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_MIDDLE.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, + landmark_sensor.clone(), Name::new("Landmark Cat Statue Middle"), )); parent.spawn(( @@ -204,11 +231,11 @@ fn spawn_landmarks(mut commands: Commands) { TransformBundle::from_transform(Transform::from_translation( LANDMARK_CAT_STATUE_RIGHT.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, + landmark_sensor.clone(), Name::new("Landmark Cat Statue Right"), )); }); + parent .spawn(( LandmarkGroup, @@ -221,8 +248,7 @@ fn spawn_landmarks(mut commands: Commands) { TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_LEFT.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, + landmark_sensor.clone(), Name::new("Landmark Fabien Statue Left"), )); parent.spawn(( @@ -230,8 +256,7 @@ fn spawn_landmarks(mut commands: Commands) { TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_MIDDLE.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, + landmark_sensor.clone(), Name::new("Landmark Fabien Statue Middle"), )); parent.spawn(( @@ -239,8 +264,7 @@ fn spawn_landmarks(mut commands: Commands) { TransformBundle::from_transform(Transform::from_translation( LANDMARK_FABIEN_STATUE_RIGHT.into(), )), - Collider::ball(LANDMARK_SENSOR_SIZE), - Sensor, + landmark_sensor, Name::new("Landmark Fabien Statue Right"), )); }); diff --git a/src/locations/temple/mod.rs b/src/locations/temple/mod.rs old mode 100644 new mode 100755 index bed2dd8..e9570bc --- a/src/locations/temple/mod.rs +++ b/src/locations/temple/mod.rs @@ -19,7 +19,7 @@ pub mod secret_room; #[derive(Component, Deref, DerefMut)] pub struct ZPosition(f32); -#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, Reflect, Component, States)] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default, Reflect, Component, States)] pub enum Location { #[default] Hall, diff --git a/src/locations/temple/secret_room.rs b/src/locations/temple/secret_room.rs index 45d887e..6aeefdc 100644 --- a/src/locations/temple/secret_room.rs +++ b/src/locations/temple/secret_room.rs @@ -44,6 +44,7 @@ pub struct SecretRoomTriggerEvent { pub started: bool, } +/// IDEA: Only remove the cover when entering the secret room #[derive(Event)] pub struct RemoveSecretRoomCoverEvent; From 5e001d1d9235ed65e8fea796045b8f26a96cd9e0 Mon Sep 17 00:00:00 2001 From: Wabtey Date: Tue, 19 Sep 2023 19:07:50 +0200 Subject: [PATCH 4/8] spawn a lot more Landmarks, fix npcs' movement, minor bug fixes - decomposition of all the constants' modules - Landmarks in Temple - spawn a vampire tourist - stop the npc when resting - adjust the `move_to` function to guide the feet of the npc to the target - Fix the BUG: all npcs having a collision with any sensor can be interact with at the same time - verify when the interaction_sensor collide with something that it's the `PlayerInteractionSensor` --- src/characters/npcs/idle.rs | 14 +- src/characters/npcs/mod.rs | 42 +- src/characters/npcs/movement.rs | 55 +- src/constants.rs | 469 ------------------ src/constants/character.rs | 116 +++++ src/constants/locations/hall.rs | 56 +++ .../locations/main_room/landmarks.rs | 429 ++++++++++++++++ src/constants/locations/main_room/mod.rs | 142 ++++++ src/constants/locations/mod.rs | 54 ++ src/constants/locations/secret_room.rs | 34 ++ src/constants/mod.rs | 29 ++ src/constants/title_screen.rs | 28 ++ src/constants/ui.rs | 20 + src/interactions.rs | 18 +- src/locations/landmarks.rs | 124 +++-- src/locations/temple/mod.rs | 1 + 16 files changed, 1031 insertions(+), 600 deletions(-) delete mode 100755 src/constants.rs create mode 100644 src/constants/character.rs create mode 100644 src/constants/locations/hall.rs create mode 100644 src/constants/locations/main_room/landmarks.rs create mode 100644 src/constants/locations/main_room/mod.rs create mode 100644 src/constants/locations/mod.rs create mode 100644 src/constants/locations/secret_room.rs create mode 100755 src/constants/mod.rs create mode 100644 src/constants/title_screen.rs create mode 100644 src/constants/ui.rs diff --git a/src/characters/npcs/idle.rs b/src/characters/npcs/idle.rs index 8624357..1504f9c 100755 --- a/src/characters/npcs/idle.rs +++ b/src/characters/npcs/idle.rs @@ -1,4 +1,5 @@ use bevy::prelude::*; +use bevy_rapier2d::prelude::Velocity; use super::{movement::NPCBehavior, NPC}; @@ -11,12 +12,19 @@ pub struct RestTime { pub fn flexing_timer( mut commands: Commands, time: Res