From 8ae016e2a9149a723efd92b604a7d00a4047bc7f Mon Sep 17 00:00:00 2001 From: Bilal Kahraman Date: Sat, 30 Nov 2024 18:02:11 +0300 Subject: [PATCH] Add simple_weapons for enemy and update shooting manager to calculate damage --- src/Camera/src/camera.cpp | 22 ++++-- src/Characters/CMakeLists.txt | 1 + src/Characters/include/Characters/enemy.h | 8 ++- src/Characters/src/enemy.cpp | 38 +++++++++- src/Characters/src/player.cpp | 1 + .../include/ShootingManager/shooting_helper.h | 47 +++++++++++++ .../ShootingManager/shooting_manager.h | 8 ++- src/ShootingManager/src/shooting_manager.cpp | 40 ++++++++--- src/State/src/enemy_state.cpp | 6 +- src/State/src/weapon_state.cpp | 2 +- src/Strike/CMakeLists.txt | 14 ++++ src/Strike/include/Strike/simple_weapon.h | 70 +++++++++++++++++++ src/Strike/include/Strike/weapon.h | 16 +++-- src/Strike/src/simple_weapon.cpp | 70 +++++++++++++++++++ src/Strike/src/weapon.cpp | 16 ++++- 15 files changed, 328 insertions(+), 31 deletions(-) create mode 100644 src/ShootingManager/include/ShootingManager/shooting_helper.h create mode 100644 src/Strike/include/Strike/simple_weapon.h create mode 100644 src/Strike/src/simple_weapon.cpp diff --git a/src/Camera/src/camera.cpp b/src/Camera/src/camera.cpp index b21246d..8bb85dc 100644 --- a/src/Camera/src/camera.cpp +++ b/src/Camera/src/camera.cpp @@ -11,7 +11,9 @@ #include "Camera/camera.h" #include "Camera/ray.h" +#include "Characters/enemy.h" #include "Core/scene.h" +#include "GameObjects/game_object.h" #include "Math/vector.h" #include @@ -139,12 +141,20 @@ void Camera2D::Calculate(const std::shared_ptr& object) { objects_[object->GetId()] = object_ray_pair; // Calculate if the object is in the crosshair - if (object_distance < crosshair_ray_->perpendicular_distance && - camera_angle_left <= 0 && camera_angle_right >= 0) { - crosshair_ray_->is_hit = true; - crosshair_ray_->perpendicular_distance = object_distance; - crosshair_ray_->object_id = object->GetId(); - crosshair_ray_->hit_point = object_pose; + if (object->GetObjectType() == ObjectType::CHARACTER_ENEMY) { + const auto bot = std::dynamic_pointer_cast(object); + if (object_distance < crosshair_ray_->perpendicular_distance && + camera_angle_left <= 0 && camera_angle_right >= 0 && + bot->IsAlive()) { + crosshair_ray_->is_hit = true; + crosshair_ray_->perpendicular_distance = + (object_ray_pair.first.perpendicular_distance + + object_ray_pair.second.perpendicular_distance) / + 2; + crosshair_ray_->distance = object_distance; + crosshair_ray_->object_id = bot->GetId(); + crosshair_ray_->hit_point = object_pose; + } } } diff --git a/src/Characters/CMakeLists.txt b/src/Characters/CMakeLists.txt index 6fb903a..3fe6aa2 100644 --- a/src/Characters/CMakeLists.txt +++ b/src/Characters/CMakeLists.txt @@ -19,5 +19,6 @@ target_link_libraries( weapon camera single_raycaster + simple_weapon ) diff --git a/src/Characters/include/Characters/enemy.h b/src/Characters/include/Characters/enemy.h index 36e1ec4..cdc7484 100644 --- a/src/Characters/include/Characters/enemy.h +++ b/src/Characters/include/Characters/enemy.h @@ -17,6 +17,8 @@ #include "GameObjects/game_object.h" #include "Math/vector.h" #include "State/enemy_state.h" +#include "Strike/simple_weapon.h" +#include "Strike/strike.h" #include #include namespace wolfenstein { @@ -31,8 +33,6 @@ struct StateConfig AnimationTime animation_time; double follow_range_max; double follow_range_min; - double attack_range; - double attack_rate; }; class EnemyFactory; @@ -47,6 +47,8 @@ class Enemy : public ICharacter, void TransitionTo(EnemyStatePtr state); bool IsPlayerInShootingRange() const; bool IsAttacked() const; + bool IsAlive() const; + void Shoot(); void SetNextPose(vector2d pose); void SetAttacked(bool value); @@ -67,6 +69,7 @@ class Enemy : public ICharacter, double GetHeight() const override; StateConfig GetStateConfig() const; Ray GetCrosshairRay() const; + std::shared_ptr GetWeapon() const; friend class EnemyFactory; @@ -86,6 +89,7 @@ class Enemy : public ICharacter, vector2d next_pose; StateConfig state_config_; EnemyStatePtr state_; + std::shared_ptr weapon_; Ray crosshair_ray; bool is_attacked_; bool is_alive_; diff --git a/src/Characters/src/enemy.cpp b/src/Characters/src/enemy.cpp index 9185e9c..ac6ac83 100644 --- a/src/Characters/src/enemy.cpp +++ b/src/Characters/src/enemy.cpp @@ -3,6 +3,8 @@ #include "Camera/single_raycaster.h" #include "CollisionManager/collision_manager.h" #include "Math/vector.h" +#include "Strike/simple_weapon.h" +#include "Strike/strike.h" #include "Utility/uuid_generator.h" #include @@ -11,13 +13,29 @@ namespace wolfenstein { namespace { auto GetBotStateConfig = [](const std::string& bot_name) -> StateConfig { if (bot_name == "soldier") { - return {{0.8}, 5.0, 1.0, 5.0, 1.0}; + return {{0.8}, 5.0, 1.0}; } else if (bot_name == "caco_demon") { - return {{0.8}, 5.0, 1.0, 5.0, 1.0}; + return {{0.8}, 5.0, 1.0}; } else if (bot_name == "cyber_demon") { - return {{0.8}, 5.0, 1.0, 5.0, 1.0}; + return {{0.8}, 5.0, 1.0}; + } + else { + throw std::invalid_argument("Invalid bot name"); + } +}; + +auto GetBotWeapon = + [](const std::string& bot_name) -> std::shared_ptr { + if (bot_name == "soldier") { + return std::make_shared(); + } + else if (bot_name == "caco_demon") { + return std::make_shared(); + } + else if (bot_name == "cyber_demon") { + return std::make_shared(); } else { throw std::invalid_argument("Invalid bot name"); @@ -35,6 +53,7 @@ Enemy::Enemy(std::string bot_name, CharacterConfig config) id_(UuidGenerator::GetInstance().GenerateUuid().bytes()), next_pose(position_.pose), state_config_(GetBotStateConfig(bot_name)), + weapon_(GetBotWeapon(bot_name)), crosshair_ray(Ray{}), is_attacked_(false), is_alive_(true) {} @@ -52,11 +71,20 @@ bool Enemy::IsAttacked() const { return is_attacked_; } +bool Enemy::IsAlive() const { + return is_alive_; +} + +void Enemy::Shoot() { + weapon_->Attack(); +} + void Enemy::Update(double delta_time) { if (!is_alive_) { return; } crosshair_ray = SingleRayCasterService::GetInstance().Cast(position_.pose); + weapon_->SetCrosshairRay(crosshair_ray); state_->Update(delta_time); if (next_pose != position_.pose) { Move(delta_time); @@ -149,6 +177,10 @@ Ray Enemy::GetCrosshairRay() const { return crosshair_ray; } +std::shared_ptr Enemy::GetWeapon() const { + return weapon_; +} + std::shared_ptr EnemyFactory::CreateEnemy(std::string bot_name, CharacterConfig config) { auto enemy_ptr = std::make_shared(bot_name, config); diff --git a/src/Characters/src/player.cpp b/src/Characters/src/player.cpp index 3a73b00..deb3916 100644 --- a/src/Characters/src/player.cpp +++ b/src/Characters/src/player.cpp @@ -29,6 +29,7 @@ void Player::Update(double delta_time) { subscriber(position_); } camera_->Update(); + weapon_->SetCrossHair(camera_->GetCrosshairRay()); } void Player::SetPose(const vector2d& pose) { diff --git a/src/ShootingManager/include/ShootingManager/shooting_helper.h b/src/ShootingManager/include/ShootingManager/shooting_helper.h new file mode 100644 index 0000000..19ff677 --- /dev/null +++ b/src/ShootingManager/include/ShootingManager/shooting_helper.h @@ -0,0 +1,47 @@ +/** + * @file shooting_helper.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-11-28 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef SHOOTING_MANAGER_INCLUDE_SHOOTING_MANAGER_SHOOTING_HELPER_H +#define SHOOTING_MANAGER_INCLUDE_SHOOTING_MANAGER_SHOOTING_HELPER_H + +#include + +namespace wolfenstein { + +inline double LinearSlope(const std::pair damage_limits, + const double range, const double distance) { + const auto linear_slope_formula = + [](const std::pair damage_limits, const double range, + const double distance) { + return ((range - distance) / range) * + (damage_limits.first - damage_limits.second) + + damage_limits.second; + }; + return linear_slope_formula(damage_limits, range, distance); +} + +inline double ExponentialSlope(const std::pair damage_limits, + const double range, const double distance) { + + const auto exp_slope_formula = + [](const std::pair damage_limits, const double range, + const double distance) { + return std::fmin(std::fmax(std::exp((range - distance) / 1.5), + damage_limits.second), + damage_limits.first); + }; + + return exp_slope_formula(damage_limits, range, distance); +} + +} // namespace wolfenstein + +#endif // SHOOTING_MANAGER_INCLUDE_SHOOTING_MANAGER_SHOOTING_HELPER_H diff --git a/src/ShootingManager/include/ShootingManager/shooting_manager.h b/src/ShootingManager/include/ShootingManager/shooting_manager.h index e1178f9..fa674ea 100644 --- a/src/ShootingManager/include/ShootingManager/shooting_manager.h +++ b/src/ShootingManager/include/ShootingManager/shooting_manager.h @@ -18,6 +18,8 @@ #include "Characters/player.h" #include "Math/vector.h" #include "NavigationManager/navigation_manager.h" +#include "Strike/simple_weapon.h" +#include "Strike/strike.h" #include #include @@ -33,12 +35,12 @@ class ShootingManager void InitManager(std::shared_ptr map, std::shared_ptr player, std::vector> enemies); - void PlayerShoot(); - void EnemyShoot(); + void PlayerShoot(const std::shared_ptr weapon); + void EnemyShoot(const std::shared_ptr weapon); private: ShootingManager() = default; - double CalculateDamage(const std::shared_ptr enemy); + double CalculateDamage(const std::shared_ptr weapon); static ShootingManager* instance_; std::shared_ptr player_; diff --git a/src/ShootingManager/src/shooting_manager.cpp b/src/ShootingManager/src/shooting_manager.cpp index b3975cf..bd15daf 100644 --- a/src/ShootingManager/src/shooting_manager.cpp +++ b/src/ShootingManager/src/shooting_manager.cpp @@ -1,5 +1,9 @@ #include "ShootingManager/shooting_manager.h" #include "Math/vector.h" +#include "ShootingManager/shooting_helper.h" +#include "Strike/simple_weapon.h" +#include "Strike/weapon.h" +#include namespace wolfenstein { @@ -20,13 +24,17 @@ void ShootingManager::InitManager(std::shared_ptr map, enemies_ = enemies; } -void ShootingManager::PlayerShoot() { +void ShootingManager::PlayerShoot(const std::shared_ptr weapon) { auto enemy = std::find_if( enemies_.begin(), enemies_.end(), [this](const auto& enemy) { return enemy->GetId() == player_->GetCrosshairRay()->object_id; }); if (enemy != enemies_.end()) { - (*enemy)->DecreaseHealth(CalculateDamage(*enemy)); + const auto damage = CalculateDamage(weapon); + if (damage == 0) { + return; + } + (*enemy)->DecreaseHealth(damage); (*enemy)->SetAttacked(true); std::cout << "Enemy Name: " << (*enemy)->GetBotName() << " Enemy health: " << (*enemy)->GetHealth() << std::endl; @@ -38,14 +46,30 @@ void ShootingManager::PlayerShoot() { } } -void ShootingManager::EnemyShoot() { - std::cout << "Enemy shoot" << std::endl; - player_->DecreaseHealth(10); - std::cout << "Player health: " << player_->GetHealth() << std::endl; +void ShootingManager::EnemyShoot(const std::shared_ptr weapon) { + std::cout << "Enemy shoot with " << weapon->GetWeaponName() << std::endl; + const auto damage = + LinearSlope(weapon->GetAttackDamage(), weapon->GetAttackRange(), + weapon->GetCrosshair().distance); + player_->DecreaseHealth(damage); + std::cout << "Damage dealt: " << damage + << " Player health: " << player_->GetHealth() << std::endl; } -double ShootingManager::CalculateDamage(const std::shared_ptr enemy) { - return 10; +double ShootingManager::CalculateDamage(const std::shared_ptr weapon) { + if (weapon->GetCrosshair()->distance > weapon->GetAttackRange()) { + return 0; + } + if (weapon->GetWeaponName() == "mp5") { + return LinearSlope(weapon->GetAttackDamage(), weapon->GetAttackRange(), + weapon->GetCrosshair()->distance); + } + if (weapon->GetWeaponName() == "shotgun") { + return ExponentialSlope(weapon->GetAttackDamage(), + weapon->GetAttackRange(), + weapon->GetCrosshair()->distance); + } + return 0; } } // namespace wolfenstein diff --git a/src/State/src/enemy_state.cpp b/src/State/src/enemy_state.cpp index 835fdaa..0971185 100644 --- a/src/State/src/enemy_state.cpp +++ b/src/State/src/enemy_state.cpp @@ -101,6 +101,8 @@ void WalkState::Reset() { } void WalkState::OnContextSet() { + attack_rate_ = context_->GetWeapon()->GetAttackRate(); + attack_range_ = context_->GetWeapon()->GetAttackRange(); animation_ = std::make_unique( context_->GetBotName() + "_walk", animation_speed_); } @@ -121,7 +123,7 @@ AttackState::~AttackState() {} void AttackState::Update(const double& delta_time) { animation_->Update(delta_time); if (attack_counter_ == 0.0) { - ShootingManager::GetInstance().EnemyShoot(); + context_->Shoot(); } if (context_->IsAttacked()) { context_->TransitionTo(std::make_shared()); @@ -139,6 +141,7 @@ void AttackState::Reset() { } void AttackState::OnContextSet() { + animation_speed_ = context_->GetWeapon()->GetAttackSpeed(); animation_ = std::make_unique( context_->GetBotName() + "_attack", animation_speed_); } @@ -197,6 +200,7 @@ void DeathState::Update(const double& delta_time) { counter += delta_time; } else { + NavigationManager::GetInstance().ResetPath(context_->GetId()); context_->SetDeath(); } } diff --git a/src/State/src/weapon_state.cpp b/src/State/src/weapon_state.cpp index cfa015e..276abee 100644 --- a/src/State/src/weapon_state.cpp +++ b/src/State/src/weapon_state.cpp @@ -54,7 +54,7 @@ void LoadedState::PullTrigger() { trigger_pulled_ = true; trigger_pull_time_ = 0; context_->DecreaseAmmo(); - ShootingManager::GetInstance().PlayerShoot(); + ShootingManager::GetInstance().PlayerShoot(context_); } // ########################################### OutOfAmmoState ########################################### diff --git a/src/Strike/CMakeLists.txt b/src/Strike/CMakeLists.txt index 0a93d66..c6ff36a 100644 --- a/src/Strike/CMakeLists.txt +++ b/src/Strike/CMakeLists.txt @@ -15,3 +15,17 @@ target_link_libraries( weapon_state ) +add_library( + simple_weapon + STATIC + src/simple_weapon.cpp +) +target_include_directories(simple_weapon PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) +target_link_libraries( + simple_weapon + PUBLIC + shooting_manager + ray +) \ No newline at end of file diff --git a/src/Strike/include/Strike/simple_weapon.h b/src/Strike/include/Strike/simple_weapon.h new file mode 100644 index 0000000..7b05135 --- /dev/null +++ b/src/Strike/include/Strike/simple_weapon.h @@ -0,0 +1,70 @@ +/** + * @file melee.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-11-30 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef STRIKE_INCLUDE_STRIKE_SIMPLE_WEAPON_H +#define STRIKE_INCLUDE_STRIKE_SIMPLE_WEAPON_H + +#include "Camera/ray.h" +#include "Strike/strike.h" +#include +#include + +namespace wolfenstein { + +class SimpleWeapon : public IStrike, + public std::enable_shared_from_this +{ + public: + virtual ~SimpleWeapon() = default; + + void SetCrosshairRay(Ray ray); + std::pair GetAttackDamage() const; + double GetAttackRange() const; + double GetAttackSpeed() const; + double GetAttackRate() const; + Ray GetCrosshair() const; + std::string GetWeaponName() const; + + protected: + std::pair attack_damage; + double attack_range; + double attack_speed; + double attack_rate; + Ray crosshair_ray; + std::string weapon_name; +}; + +class Melee : public SimpleWeapon +{ + public: + Melee(); + ~Melee() = default; + void Attack() override; +}; + +class Rifle : public SimpleWeapon +{ + public: + Rifle(); + ~Rifle() = default; + void Attack() override; +}; + +class LaserGun : public SimpleWeapon +{ + public: + LaserGun(); + ~LaserGun() = default; + void Attack() override; +}; + +} // namespace wolfenstein +#endif // STRIKE_INCLUDE_STRIKE_SIMPLE_WEAPON_H diff --git a/src/Strike/include/Strike/weapon.h b/src/Strike/include/Strike/weapon.h index 6698ab5..f2d4972 100644 --- a/src/Strike/include/Strike/weapon.h +++ b/src/Strike/include/Strike/weapon.h @@ -15,23 +15,25 @@ #include "State/weapon_state.h" #include "Strike/strike.h" #include +#include #include namespace wolfenstein { +class Ray; struct WeaponConfig { WeaponConfig(std::string weapon_name, size_t ammo_capacity, - double attack_damage, double attack_range, double attack_speed, - double reload_speed) + double attack_damage_max, double attack_damage_min, + double attack_range, double attack_speed, double reload_speed) : weapon_name(weapon_name), ammo_capacity(ammo_capacity), - attack_damage(attack_damage), + attack_damage(attack_damage_max, attack_damage_min), attack_range(attack_range), attack_speed(attack_speed), reload_speed(reload_speed) {} std::string weapon_name; size_t ammo_capacity; - double attack_damage; + std::pair attack_damage; double attack_range; double attack_speed; double reload_speed; @@ -55,14 +57,17 @@ class Weapon : public IStrike, public std::enable_shared_from_this void IncreaseAmmo(size_t amount); void DecreaseAmmo(); void DecreaseAmmo(size_t amount); + void SetCrossHair(std::shared_ptr crosshair); + size_t GetAmmo() const; size_t GetAmmoCapacity() const; - double GetAttackDamage() const; + std::pair GetAttackDamage() const; double GetAttackRange() const; double GetAttackSpeed() const; double GetReloadSpeed() const; std::string GetWeaponName() const; int GetTextureId() const; + std::shared_ptr GetCrosshair() const; private: WeaponConfig weapon_properties_; @@ -70,6 +75,7 @@ class Weapon : public IStrike, public std::enable_shared_from_this WeaponStatePtr state_; bool cooldown_; double attack_time_; + std::shared_ptr crosshair_; }; } // namespace wolfenstein diff --git a/src/Strike/src/simple_weapon.cpp b/src/Strike/src/simple_weapon.cpp new file mode 100644 index 0000000..5d28170 --- /dev/null +++ b/src/Strike/src/simple_weapon.cpp @@ -0,0 +1,70 @@ +#include "Strike/simple_weapon.h" +#include "ShootingManager/shooting_manager.h" + +namespace wolfenstein { + +void SimpleWeapon::SetCrosshairRay(Ray ray) { + crosshair_ray = ray; +} + +std::pair SimpleWeapon::GetAttackDamage() const { + return attack_damage; +} + +double SimpleWeapon::GetAttackRange() const { + return attack_range; +} + +double SimpleWeapon::GetAttackSpeed() const { + return attack_speed; +} + +double SimpleWeapon::GetAttackRate() const { + return attack_rate; +} + +Ray SimpleWeapon::GetCrosshair() const { + return crosshair_ray; +} + +std::string SimpleWeapon::GetWeaponName() const { + return weapon_name; +} + +Melee::Melee() { + attack_damage = std::make_pair(17, 8); + attack_range = 2.0; + attack_speed = 0.5; + attack_rate = 1.0; + weapon_name = "melee"; +} + +void Melee::Attack() { + ShootingManager::GetInstance().EnemyShoot(shared_from_this()); +} + +Rifle::Rifle() { + attack_damage = std::make_pair(15, 5); + attack_range = 5.0; + attack_speed = 0.7; + attack_rate = 1.0; + weapon_name = "rifle"; +} + +void Rifle::Attack() { + ShootingManager::GetInstance().EnemyShoot(shared_from_this()); +} + +LaserGun::LaserGun() { + attack_damage = std::make_pair(19, 10); + attack_range = 7.0; + attack_speed = 1.0; + attack_rate = 1.0; + weapon_name = "laser gun"; +} + +void LaserGun::Attack() { + ShootingManager::GetInstance().EnemyShoot(shared_from_this()); +} + +} // namespace wolfenstein diff --git a/src/Strike/src/weapon.cpp b/src/Strike/src/weapon.cpp index 5f767c2..c57f6f5 100644 --- a/src/Strike/src/weapon.cpp +++ b/src/Strike/src/weapon.cpp @@ -3,6 +3,7 @@ #include "TimeManager/time_manager.h" #include #include +#include #include #include namespace wolfenstein { @@ -10,7 +11,10 @@ namespace wolfenstein { namespace { auto GetWeaponConfig = [](const std::string& weapon_name) -> WeaponConfig { if (weapon_name == "mp5") { - return {"mp5", 10, 10, 10, 0.3, 1.5}; + return {"mp5", 8, 15, 2, 8, 0.5, 1.5}; + } + else if (weapon_name == "shotgun") { + return {"shotgun", 2, 60, 2, 7, 0.7, 3.5}; } else { throw std::invalid_argument("Invalid weapon name"); @@ -75,6 +79,10 @@ void Weapon::DecreaseAmmo(size_t amount) { ammo_ -= amount; } +void Weapon::SetCrossHair(std::shared_ptr crosshair) { + crosshair_ = crosshair; +} + size_t Weapon::GetAmmo() const { return ammo_; } @@ -83,7 +91,7 @@ size_t Weapon::GetAmmoCapacity() const { return weapon_properties_.ammo_capacity; } -double Weapon::GetAttackDamage() const { +std::pair Weapon::GetAttackDamage() const { return weapon_properties_.attack_damage; } @@ -107,4 +115,8 @@ int Weapon::GetTextureId() const { return state_->GetCurrentFrame(); } +std::shared_ptr Weapon::GetCrosshair() const { + return crosshair_; +} + } // namespace wolfenstein \ No newline at end of file