diff --git a/CMakeLists.txt b/CMakeLists.txt index ff527ef..e382f23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ add_subdirectory(src/Graphics) add_subdirectory(src/Map) add_subdirectory(src/Math) add_subdirectory(src/NavigationManager) +add_subdirectory(src/Strike) add_subdirectory(src/TextureManager) add_subdirectory(src/TimeManager) add_subdirectory(src/Utility) diff --git a/app/main.cpp b/app/main.cpp index 6fa37e9..3fb8569 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -13,7 +13,7 @@ int main() { using namespace wolfenstein; - GeneralConfig config(2560, 1440, 0, 50, 120, 10.0, ToRadians(60.0), true); + GeneralConfig config(800, 600, 0, 50, 120, 10.0, ToRadians(60.0), false); Game game(config); game.Run(); diff --git a/src/Characters/CMakeLists.txt b/src/Characters/CMakeLists.txt index 60402c8..6c54425 100644 --- a/src/Characters/CMakeLists.txt +++ b/src/Characters/CMakeLists.txt @@ -15,5 +15,6 @@ target_link_libraries( collision_manager animation SDL2 + shotgun ) diff --git a/src/Characters/include/Characters/character.h b/src/Characters/include/Characters/character.h index 4972461..33d9361 100644 --- a/src/Characters/include/Characters/character.h +++ b/src/Characters/include/Characters/character.h @@ -12,7 +12,7 @@ #ifndef CHARACTERS_INCLUDE_CHARACTER_H #define CHARACTERS_INCLUDE_CHARACTER_H -#include "GameObjects/game_object.h" +#include "Math/vector.h" namespace wolfenstein { diff --git a/src/Characters/include/Characters/enemy.h b/src/Characters/include/Characters/enemy.h index 75923a6..7ced346 100644 --- a/src/Characters/include/Characters/enemy.h +++ b/src/Characters/include/Characters/enemy.h @@ -14,6 +14,7 @@ #include "Animation/walk_animation.h" #include "Characters/character.h" +#include "GameObjects/game_object.h" #include "Math/vector.h" namespace wolfenstein { diff --git a/src/Characters/include/Characters/player.h b/src/Characters/include/Characters/player.h index 168d923..f39bee9 100644 --- a/src/Characters/include/Characters/player.h +++ b/src/Characters/include/Characters/player.h @@ -13,7 +13,10 @@ #define CHARACTERS_PLAYER_H #include "Characters/character.h" +#include "GameObjects/game_object.h" +#include "Strike/shotgun.h" #include +#include namespace wolfenstein { @@ -32,7 +35,7 @@ class Player : public ICharacter, public IGameObject void SetPosition(Position2D position) override; Position2D GetPosition() const override; std::string GetId() const override; - int GetTextureId() const override { return -1; } + int GetTextureId() const override { return shotgun_->GetTextureId(); } double GetWidth() const override { return -1; } double GetHeight() const override { return -1; } void SubscribeToPlayerPosition(std::function subscriber); @@ -40,11 +43,13 @@ class Player : public ICharacter, public IGameObject private: void Move(double delta_time); void Rotate(double delta_time); + void Shoot(); Position2D position_; double rotation_speed_; double translation_speed_; std::string id_; + std::shared_ptr shotgun_; std::vector> player_position_subscribers_; }; diff --git a/src/Characters/src/player.cpp b/src/Characters/src/player.cpp index a498899..614788c 100644 --- a/src/Characters/src/player.cpp +++ b/src/Characters/src/player.cpp @@ -11,9 +11,11 @@ Player::Player(CharacterConfig& config) rotation_speed_(config.rotation_speed), translation_speed_(config.translation_speed) { id_ = UuidGenerator::GetInstance().GenerateUuid().bytes(); + shotgun_ = std::make_shared(); } void Player::Update(double delta_time) { + Shoot(); Move(delta_time); Rotate(delta_time); for (auto& subscriber : player_position_subscribers_) { @@ -99,4 +101,10 @@ void Player::Rotate(double delta_time) { } } +void Player::Shoot() { + if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LMASK) { + shotgun_->Attack(); + } +} + } // namespace wolfenstein diff --git a/src/Core/include/Core/game.h b/src/Core/include/Core/game.h index fba0e13..72444ec 100644 --- a/src/Core/include/Core/game.h +++ b/src/Core/include/Core/game.h @@ -54,7 +54,6 @@ class Game std::shared_ptr renderer_; std::shared_ptr scene_; - std::shared_ptr time_manager_; std::shared_ptr camera_; std::shared_ptr player_; std::shared_ptr map_; diff --git a/src/Core/src/game.cpp b/src/Core/src/game.cpp index 7ca6c17..43dde28 100644 --- a/src/Core/src/game.cpp +++ b/src/Core/src/game.cpp @@ -7,6 +7,7 @@ #include "Graphics/renderer.h" #include "Math/vector.h" #include "NavigationManager/navigation_manager.h" +#include "TimeManager/time_manager.h" #include #include #include @@ -32,8 +33,6 @@ void Game::Init() { scene_ = std::make_shared(); scene_->SetMap(map_); - time_manager_ = std::make_shared(); - RenderConfig render_config = {config_.screen_width, config_.screen_height, config_.padding, config_.scale, config_.fps, config_.view_distance, @@ -89,7 +88,7 @@ void Game::Init() { vector2d(12.1, 10.9), std::make_shared(animation_green_light), 0.2, 0.9)); is_running_ = true; - time_manager_->InitClock(); + TimeManager::GetInstance().InitClock(); } void Game::CheckEvent() { @@ -130,8 +129,8 @@ void Game::CheckEvent() { void Game::Run() { while (is_running_) { CheckEvent(); - time_manager_->CalculateDeltaTime(); - scene_->Update(time_manager_->GetDeltaTime()); + TimeManager::GetInstance().CalculateDeltaTime(); + scene_->Update(TimeManager::GetInstance().GetDeltaTime()); camera_->Update(scene_); switch (render_type_) { case RenderType::TEXTURE: diff --git a/src/Graphics/include/Graphics/renderer.h b/src/Graphics/include/Graphics/renderer.h index 6b9c4fd..5b88a29 100644 --- a/src/Graphics/include/Graphics/renderer.h +++ b/src/Graphics/include/Graphics/renderer.h @@ -93,6 +93,8 @@ class Renderer int CalculateHorizontalSlice(const double& angle, const std::shared_ptr camera_ptr); std::tuple CalculateVerticalSlice(const double& distance); + void RenderWeapon(const std::shared_ptr& player_ptr, + RenderQueue& render_queue); void RenderTextures(RenderQueue& render_queue); // Render 2D diff --git a/src/Graphics/src/renderer.cpp b/src/Graphics/src/renderer.cpp index b068843..f5b36e9 100644 --- a/src/Graphics/src/renderer.cpp +++ b/src/Graphics/src/renderer.cpp @@ -72,6 +72,7 @@ void Renderer::RenderScene(const std::shared_ptr& scene_ptr, RenderBackground(); RenderWalls(scene_ptr->GetMap(), camera_ptr, render_queue); RenderObjects(scene_ptr->GetObjects(), camera_ptr, render_queue); + RenderWeapon(scene_ptr->GetPlayer(), render_queue); RenderTextures(render_queue); SDL_RenderPresent(renderer_); } @@ -196,6 +197,22 @@ std::tuple Renderer::CalculateVerticalSlice( return std::make_tuple(line_height, draw_start, draw_end); } +void Renderer::RenderWeapon(const std::shared_ptr& player_ptr, + RenderQueue& render_queue) { + + auto texture_id = player_ptr->GetTextureId(); + const auto texture_height = + TextureManager::GetInstance().GetTexture(texture_id).height; + const auto texture_width = + TextureManager::GetInstance().GetTexture(texture_id).width; + const auto width_slice = config_.width / 6; + const auto height_slice = config_.height / 3; + SDL_Rect src_rect{0, 0, texture_width, texture_height}; + SDL_Rect dest_rect{3 * width_slice - width_slice / 2, 2 * height_slice, + width_slice, height_slice}; + render_queue.push({texture_id, src_rect, dest_rect, 0.0}); +} + void Renderer::RenderTextures(RenderQueue& render_queue) { while (!render_queue.empty()) { auto renderable_texture = render_queue.top(); diff --git a/src/Strike/CMakeLists.txt b/src/Strike/CMakeLists.txt new file mode 100644 index 0000000..3c628bc --- /dev/null +++ b/src/Strike/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library( + shotgun + STATIC + src/shotgun.cpp +) +target_include_directories(shotgun PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) +target_link_libraries( + shotgun + PUBLIC + animation + time_manager +) + diff --git a/src/Strike/include/Strike/shotgun.h b/src/Strike/include/Strike/shotgun.h new file mode 100644 index 0000000..1fbfb6d --- /dev/null +++ b/src/Strike/include/Strike/shotgun.h @@ -0,0 +1,42 @@ +/** + * @file shotgun.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-08-29 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef STRIKE_INCLUDE_STRIKE_SHOTGUN_H +#define STRIKE_INCLUDE_STRIKE_SHOTGUN_H + +#include "Animation/time_based_single_animation.h" +#include "Strike/weapon.h" +#include + +namespace wolfenstein { + +class Shotgun : public IWeapon +{ + public: + Shotgun(); + ~Shotgun() = default; + + void Attack() override; + int GetTextureId() const; + + private: + void AttackAnimation(); + double attack_speed_; + double attack_damage_; + std::shared_ptr animation_; + + bool cooldown_; + double last_attack_time_; +}; + +} // namespace wolfenstein + +#endif // STRIKE_INCLUDE_STRIKE_SHOTGUN_H diff --git a/src/Strike/include/Strike/strike.h b/src/Strike/include/Strike/strike.h new file mode 100644 index 0000000..f1b7ea5 --- /dev/null +++ b/src/Strike/include/Strike/strike.h @@ -0,0 +1,27 @@ +/** + * @file strike.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-08-29 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef STRIKE_INCLUDE_STRIKE_STRIKE_H +#define STRIKE_INCLUDE_STRIKE_STRIKE_H + +namespace wolfenstein { + +class IStrike +{ + public: + virtual ~IStrike() = default; + + virtual void Attack() = 0; +}; + +} // namespace wolfenstein + +#endif // STRIKE_INCLUDE_STRIKE_STRIKE_H \ No newline at end of file diff --git a/src/Strike/include/Strike/weapon.h b/src/Strike/include/Strike/weapon.h new file mode 100644 index 0000000..9ca57c0 --- /dev/null +++ b/src/Strike/include/Strike/weapon.h @@ -0,0 +1,27 @@ +/** + * @file weapon.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-08-29 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef STRIKE_INCLUDE_STRIKE_WEAPON_H +#define STRIKE_INCLUDE_STRIKE_WEAPON_H + +namespace wolfenstein { + +class IWeapon +{ + public: + virtual ~IWeapon() = default; + + virtual void Attack() = 0; +}; + +} // namespace wolfenstein + +#endif // STRIKE_INCLUDE_STRIKE_WEAPON_H diff --git a/src/Strike/src/shotgun.cpp b/src/Strike/src/shotgun.cpp new file mode 100644 index 0000000..478c9bc --- /dev/null +++ b/src/Strike/src/shotgun.cpp @@ -0,0 +1,45 @@ +#include "Strike/shotgun.h" +#include "TimeManager/time_manager.h" +#include +#include + +namespace wolfenstein { + +Shotgun::Shotgun() : attack_speed_(0.6), attack_damage_(10) { + std::vector tex_ids{90, 91, 92, 93, 94, 95}; + animation_ = + std::make_shared(tex_ids, attack_speed_ / tex_ids.size()); + cooldown_ = false; +} + +int Shotgun::GetTextureId() const { + return animation_->GetCurrentFrame(); +} + +void Shotgun::Attack() { + // If the weapon is not in cooldown, attack and set the cooldown true + if (!cooldown_) { + cooldown_ = true; + last_attack_time_ = TimeManager::GetInstance().GetCurrentTime(); + + // Create a new thread to play the attack animation + // Use attack speed to calculate the time to wait + std::thread attack_thread(&Shotgun::AttackAnimation, this); + attack_thread.detach(); + } +} +// BUG: Segmentation fault if game closes while the thread is running +void Shotgun::AttackAnimation() { + auto attack_time = last_attack_time_; + auto current_time = TimeManager::GetInstance().GetCurrentTime(); + while (current_time - last_attack_time_ < attack_speed_) { + auto time_elapsed = current_time - attack_time; + animation_->Update(time_elapsed); + attack_time = current_time; + current_time = TimeManager::GetInstance().GetCurrentTime(); + } + animation_->Reset(); + cooldown_ = false; +} + +} // namespace wolfenstein diff --git a/src/TimeManager/include/TimeManager/time_manager.h b/src/TimeManager/include/TimeManager/time_manager.h index 5362081..43464a3 100644 --- a/src/TimeManager/include/TimeManager/time_manager.h +++ b/src/TimeManager/include/TimeManager/time_manager.h @@ -13,13 +13,18 @@ #define TIME_MANAGER_INCLUDE_TIME_MANAGER_H_ #include +#include namespace wolfenstein { class TimeManager { public: - TimeManager() = default; + static TimeManager& GetInstance(); + + TimeManager(const TimeManager&) = delete; + TimeManager& operator=(const TimeManager&) = delete; + ~TimeManager() = default; void InitClock(); void CalculateDeltaTime(); @@ -29,10 +34,17 @@ class TimeManager double GetFramePerSecond(); double GetCurrentTime(); + std::string GetTime(); + private: + TimeManager() = default; + static TimeManager* instance_; + std::chrono::duration delta_time; std::chrono::time_point previos_time_point; + std::chrono::time_point + initial_time_point; }; } // namespace wolfenstein diff --git a/src/TimeManager/src/time_manager.cpp b/src/TimeManager/src/time_manager.cpp index 9a1bc2e..a5775a5 100644 --- a/src/TimeManager/src/time_manager.cpp +++ b/src/TimeManager/src/time_manager.cpp @@ -3,8 +3,18 @@ namespace wolfenstein { +TimeManager* TimeManager::instance_ = nullptr; + +TimeManager& TimeManager::GetInstance() { + if (instance_ == nullptr) { + instance_ = new TimeManager(); + } + return *instance_; +} + void TimeManager::InitClock() { previos_time_point = std::chrono::high_resolution_clock::now(); + initial_time_point = previos_time_point; } void TimeManager::CalculateDeltaTime() { @@ -45,4 +55,15 @@ double TimeManager::GetCurrentTime() { return current_time.count(); } +std::string TimeManager::GetTime() { + auto time_passed = + std::chrono::high_resolution_clock::now() - initial_time_point; + auto time_passed_seconds = + std::chrono::duration_cast(time_passed); + auto time_passed_milliseconds = + std::chrono::duration_cast(time_passed); + return std::to_string(time_passed_seconds.count()) + "." + + std::to_string(time_passed_milliseconds.count() % 1000) + "s"; +} + } // namespace wolfenstein