diff --git a/assets/font/EternalAncient.ttf b/assets/font/EternalAncient.ttf new file mode 100644 index 0000000..34764d9 --- /dev/null +++ b/assets/font/EternalAncient.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b81a2c10397f52d1be62253b5ea30b7702adf372a16b7815889b2a85da4e1edd +size 61084 diff --git a/assets/sprites/weapon/shotgun/0.png b/assets/sprites/weapon/shotgun/0.png deleted file mode 100644 index 9620562..0000000 Binary files a/assets/sprites/weapon/shotgun/0.png and /dev/null differ diff --git a/assets/sprites/weapon/shotgun/1.png b/assets/sprites/weapon/shotgun/1.png deleted file mode 100644 index 5f70f0b..0000000 Binary files a/assets/sprites/weapon/shotgun/1.png and /dev/null differ diff --git a/assets/sprites/weapon/shotgun/2.png b/assets/sprites/weapon/shotgun/2.png deleted file mode 100644 index e2420b7..0000000 Binary files a/assets/sprites/weapon/shotgun/2.png and /dev/null differ diff --git a/assets/sprites/weapon/shotgun/3.png b/assets/sprites/weapon/shotgun/3.png deleted file mode 100644 index 2f8cc93..0000000 Binary files a/assets/sprites/weapon/shotgun/3.png and /dev/null differ diff --git a/assets/sprites/weapon/shotgun/4.png b/assets/sprites/weapon/shotgun/4.png deleted file mode 100644 index 7db7e3d..0000000 Binary files a/assets/sprites/weapon/shotgun/4.png and /dev/null differ diff --git a/assets/sprites/weapon/shotgun/5.png b/assets/sprites/weapon/shotgun/5.png deleted file mode 100644 index 6d845e3..0000000 Binary files a/assets/sprites/weapon/shotgun/5.png and /dev/null differ diff --git a/assets/textures/damage_taken.png b/assets/textures/damage_taken.png new file mode 100644 index 0000000..de700d0 --- /dev/null +++ b/assets/textures/damage_taken.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cec6ce7c8b37e9cb8b7ccdbfe1518debc1ee0107d8a4afb8b43bc88f83a3c455 +size 161960 diff --git a/assets/textures/game_over.png b/assets/textures/game_over.png new file mode 100644 index 0000000..373364c --- /dev/null +++ b/assets/textures/game_over.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f910434444c327807bc099f79716c8bd11e21ebdc15072085e9205f3efc3d698 +size 151824 diff --git a/assets/textures/menu_background.png b/assets/textures/menu_background.png new file mode 100644 index 0000000..2f82b40 --- /dev/null +++ b/assets/textures/menu_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:046dcfe7dc7fd36a64e9bb2424c71dcddfa160d0179d8abdcf112db3c0d2ed2c +size 4318128 diff --git a/assets/textures/menu_background_2.jpg b/assets/textures/menu_background_2.jpg new file mode 100644 index 0000000..ac560c8 Binary files /dev/null and b/assets/textures/menu_background_2.jpg differ diff --git a/assets/textures/win.png b/assets/textures/win.png new file mode 100644 index 0000000..4b8df0a --- /dev/null +++ b/assets/textures/win.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c77e46f4249ce839400ba0988d3366d2b833d11360542c08cce0cc9f7f48fe3 +size 47694 diff --git a/src/Camera/include/Camera/camera.h b/src/Camera/include/Camera/camera.h index 660586d..30d42fb 100644 --- a/src/Camera/include/Camera/camera.h +++ b/src/Camera/include/Camera/camera.h @@ -26,7 +26,7 @@ struct Camera2DConfig { Camera2DConfig(int width, double fov, double depth) : width(width), fov(fov), depth(depth) {} - + int width; double fov; double depth; diff --git a/src/Characters/include/Characters/player.h b/src/Characters/include/Characters/player.h index 53b362f..0ced59c 100644 --- a/src/Characters/include/Characters/player.h +++ b/src/Characters/include/Characters/player.h @@ -31,6 +31,7 @@ class Player : public ICharacter, public IGameObject void Update(double delta_time) override; + void SetWeapon(std::shared_ptr weapon); void SetPose(const vector2d& pose) override; ObjectType GetObjectType() const override; vector2d GetPose() const override; @@ -44,6 +45,8 @@ class Player : public ICharacter, public IGameObject double GetWidth() const override; double GetHeight() const override; std::shared_ptr GetCrosshairRay() const; + std::pair IsDamaged() const; + bool IsAlive() const; void SubscribeToPlayerPosition(std::function subscriber); private: @@ -51,6 +54,9 @@ class Player : public ICharacter, public IGameObject void Rotate(double delta_time); void ShootOrReload(); + bool is_alive_{true}; + bool damaged_{false}; + double damage_counter_{0.0}; Position2D position_; double rotation_speed_; double translation_speed_; diff --git a/src/Characters/src/player.cpp b/src/Characters/src/player.cpp index 610a23b..d9cf635 100644 --- a/src/Characters/src/player.cpp +++ b/src/Characters/src/player.cpp @@ -15,7 +15,7 @@ Player::Player(CharacterConfig& config, std::shared_ptr& camera) translation_speed_(config.translation_speed) { id_ = UuidGenerator::GetInstance().GenerateUuid().bytes(); camera_ = camera; - weapon_ = std::make_shared("shotgun"); + weapon_ = std::make_shared("mp5"); WeaponStatePtr loaded_state = std::make_shared(); weapon_->TransitionTo(loaded_state); } @@ -31,6 +31,18 @@ void Player::Update(double delta_time) { } }(delta_time); + [this](double delta_time) { + if (!damaged_) { + damage_counter_ = 0; + } + else { + damage_counter_ += delta_time; + if (damage_counter_ >= 1.0) { + damaged_ = false; + } + } + }(delta_time); + ShootOrReload(); weapon_->Update(delta_time); Move(delta_time); @@ -42,6 +54,10 @@ void Player::Update(double delta_time) { weapon_->SetCrossHair(camera_->GetCrosshairRay()); } +void Player::SetWeapon(std::shared_ptr weapon) { + weapon_ = weapon; +} + void Player::SetPose(const vector2d& pose) { position_.pose = pose; } @@ -65,7 +81,10 @@ void Player::IncreaseHealth(double amount) { void Player::DecreaseHealth(double amount) { health_ -= amount; - health_ = std::max(health_, 0.0); + if (health_ <= 0.0) { + is_alive_ = false; + } + damaged_ = true; } double Player::GetHealth() const { @@ -94,6 +113,14 @@ std::shared_ptr Player::GetCrosshairRay() const { return camera_->GetCrosshairRay(); } +std::pair Player::IsDamaged() const { + return {damaged_, damage_counter_}; +} + +bool Player::IsAlive() const { + return is_alive_; +} + void Player::SubscribeToPlayerPosition( std::function updator) { player_position_subscribers_.push_back(updator); diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt index c250b12..bc3cb8b 100644 --- a/src/Core/CMakeLists.txt +++ b/src/Core/CMakeLists.txt @@ -45,4 +45,6 @@ target_link_libraries( renderer_interface renderer_2d renderer_3d + renderer_menu + renderer_result ) diff --git a/src/Core/include/Core/game.h b/src/Core/include/Core/game.h index bf560b4..72d403a 100644 --- a/src/Core/include/Core/game.h +++ b/src/Core/include/Core/game.h @@ -19,6 +19,8 @@ #include "Graphics/renderer_2d.h" #include "Graphics/renderer_3d.h" #include "Graphics/renderer_interface.h" +#include "Graphics/renderer_menu.h" +#include "Graphics/renderer_result.h" #include "Map/map.h" #include "Math/vector.h" #include "TextureManager/texture_manager.h" @@ -62,7 +64,8 @@ class Game private: void Init(); - void CheckEvent(); + void CheckGameEvent(); + void CheckMenuEvent(); void Update(); void Render(); void PrepareEnemies(); @@ -70,13 +73,17 @@ class Game void PrepareStaticObjects(); std::shared_ptr renderer_; + std::shared_ptr menu_; std::shared_ptr renderer_context_; + std::shared_ptr renderer_result_; std::shared_ptr scene_; std::shared_ptr player_; std::shared_ptr map_; GeneralConfig config_; bool is_running_; + bool is_menu_; + bool is_result_; RenderType render_type_; }; diff --git a/src/Core/include/Core/scene.h b/src/Core/include/Core/scene.h index 269c6dc..59f19b9 100644 --- a/src/Core/include/Core/scene.h +++ b/src/Core/include/Core/scene.h @@ -19,7 +19,6 @@ #include "Characters/player.h" #include "GameObjects/game_object.h" #include "Map/map.h" -#include "CollisionManager/collision_manager.h" namespace wolfenstein { diff --git a/src/Core/src/game.cpp b/src/Core/src/game.cpp index a7b28c0..0fc5ed7 100644 --- a/src/Core/src/game.cpp +++ b/src/Core/src/game.cpp @@ -10,6 +10,7 @@ #include "State/enemy_state.h" #include "TextureManager/texture_manager.h" #include "TimeManager/time_manager.h" +#include #include #include #include @@ -43,11 +44,14 @@ void Game::Init() { config_.padding, config_.scale, config_.fps, config_.view_distance, config_.fov, config_.fullscreen}; - + renderer_context_ = std::make_shared( "Wolfenstein", render_config, camera_); renderer_ = std::make_shared(renderer_context_); + renderer_->SetScene(scene_); + + menu_ = std::make_shared(renderer_context_); CharacterConfig player_config = {Position2D({3, 1.5}, 1.50), 2.0, 0.4, 0.4, 1.0}; @@ -78,19 +82,54 @@ void Game::Init() { ShootingManager::GetInstance().InitManager(map_, player_, scene_->GetEnemies()); NavigationManager::GetInstance().InitManager(map_, scene_->GetEnemies()); - - is_running_ = true; TimeManager::GetInstance().InitClock(); + is_running_ = false; + is_result_ = false; + is_menu_ = true; +} + +void Game::CheckMenuEvent() { + + SDL_Event event; + while (SDL_PollEvent(&event)) { + // When user close the window + if (event.type == SDL_QUIT || + (event.type == SDL_EventType::SDL_KEYDOWN && + event.key.keysym.sym == SDLK_ESCAPE)) { + is_running_ = false; + is_menu_ = false; + } + + // When user press a key + if (event.type == SDL_KEYDOWN) { + if (event.key.keysym.sym == SDLK_SPACE) { + player_->SetWeapon(menu_->GetSelectedWeapon()); + is_menu_ = false; + is_running_ = true; + } + // left arrow + if (event.key.keysym.sym == SDLK_LEFT) { + menu_->ChangeSelection(-1); + } + // right arrow + if (event.key.keysym.sym == SDLK_RIGHT) { + menu_->ChangeSelection(1); + } + } + } } -void Game::CheckEvent() { +void Game::CheckGameEvent() { + SDL_Event event; while (SDL_PollEvent(&event)) { + // When user close the window if (event.type == SDL_QUIT || (event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { is_running_ = false; + is_menu_ = false; } // When user alt tab the window @@ -110,22 +149,53 @@ void Game::CheckEvent() { render_type_ == RenderType::TEXTURE) { render_type_ = RenderType::LINE; renderer_ = std::make_shared(renderer_context_); + renderer_->SetScene(scene_); } else if (event.key.keysym.sym == SDLK_p && render_type_ == RenderType::LINE) { render_type_ = RenderType::TEXTURE; renderer_ = std::make_shared(renderer_context_); + renderer_->SetScene(scene_); } } } } void Game::Run() { + + while (is_menu_) { + CheckMenuEvent(); + TimeManager::GetInstance().CalculateDeltaTime(); + menu_->Render(); + SDL_WarpMouseInWindow(nullptr, 400, 300); + } + while (is_running_) { - CheckEvent(); + CheckGameEvent(); TimeManager::GetInstance().CalculateDeltaTime(); scene_->Update(TimeManager::GetInstance().GetDeltaTime()); - renderer_->RenderScene(scene_); + renderer_->RenderScene(); + // Check if player is dead + if (!player_->IsAlive()) { + is_running_ = false; + is_result_ = true; + renderer_result_ = std::make_shared( + renderer_context_, + TextureManager::GetInstance().GetTexture(10)); + } + } + + while (is_result_) { + SDL_Event event; + SDL_PollEvent(&event); + if (event.type == SDL_QUIT || + (event.type == SDL_EventType::SDL_KEYDOWN && + event.key.keysym.sym == SDLK_ESCAPE)) { + is_result_ = false; + } + + TimeManager::GetInstance().CalculateDeltaTime(); + renderer_result_->Render(); } } diff --git a/src/Graphics/CMakeLists.txt b/src/Graphics/CMakeLists.txt index c9566b5..acb62bf 100644 --- a/src/Graphics/CMakeLists.txt +++ b/src/Graphics/CMakeLists.txt @@ -47,3 +47,33 @@ target_link_libraries( PUBLIC renderer_interface ) + +add_library( + renderer_menu + STATIC + src/renderer_menu.cpp +) +target_include_directories(renderer_menu PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include +) +target_link_libraries( + renderer_menu + PUBLIC + renderer_interface +) + +add_library( + renderer_result + STATIC + src/renderer_result.cpp +) +target_include_directories(renderer_result PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include +) +target_link_libraries( + renderer_result + PUBLIC + renderer_interface +) \ No newline at end of file diff --git a/src/Graphics/include/Graphics/renderer_2d.h b/src/Graphics/include/Graphics/renderer_2d.h index 66cbe4e..7d7d4d9 100644 --- a/src/Graphics/include/Graphics/renderer_2d.h +++ b/src/Graphics/include/Graphics/renderer_2d.h @@ -21,7 +21,7 @@ class Renderer2D : public IRenderer public: using IRenderer::IRenderer; ~Renderer2D() = default; - void RenderScene(const std::shared_ptr& scene_ptr) override; + void RenderScene() override; private: void RenderMap(const std::shared_ptr map_ptr); diff --git a/src/Graphics/include/Graphics/renderer_3d.h b/src/Graphics/include/Graphics/renderer_3d.h index 6bcbc0d..2a299ff 100644 --- a/src/Graphics/include/Graphics/renderer_3d.h +++ b/src/Graphics/include/Graphics/renderer_3d.h @@ -51,7 +51,7 @@ class Renderer3D : public IRenderer public: using IRenderer::IRenderer; ~Renderer3D() = default; - void RenderScene(const std::shared_ptr& scene_ptr) override; + void RenderScene() override; private: void RenderBackground(); @@ -68,6 +68,7 @@ class Renderer3D : public IRenderer void RenderWeapon(const std::shared_ptr& player_ptr, RenderQueue& render_queue); void RenderTextures(RenderQueue& render_queue); + void RenderHUD(const std::shared_ptr& player_ptr); }; // class Renderer3D } // namespace wolfenstein diff --git a/src/Graphics/include/Graphics/renderer_interface.h b/src/Graphics/include/Graphics/renderer_interface.h index 407148a..8331845 100644 --- a/src/Graphics/include/Graphics/renderer_interface.h +++ b/src/Graphics/include/Graphics/renderer_interface.h @@ -15,6 +15,7 @@ #include "Camera/camera.h" #include "Core/scene.h" #include +#include #include namespace wolfenstein { @@ -49,12 +50,14 @@ class RendererContext std::shared_ptr& camera); ~RendererContext(); SDL_Renderer* GetRenderer() const; + TTF_Font* GetFont() const; SDL_Window* GetWindow() const; RenderConfig GetConfig() const; std::shared_ptr GetCamera() const; private: SDL_Renderer* renderer_; + TTF_Font* font_; SDL_Window* window_; RenderConfig config_; std::shared_ptr camera_ptr; @@ -66,14 +69,16 @@ class IRenderer IRenderer(std::shared_ptr context); virtual ~IRenderer() = default; - virtual void RenderScene(const std::shared_ptr& scene_ptr) = 0; + virtual void RenderScene() = 0; + void SetScene(const std::shared_ptr& scene_ptr); + protected: void ClearScreen(); std::shared_ptr GetContext() const; - protected: std::shared_ptr context_; + std::shared_ptr scene_; }; } // namespace wolfenstein diff --git a/src/Graphics/include/Graphics/renderer_menu.h b/src/Graphics/include/Graphics/renderer_menu.h new file mode 100644 index 0000000..eaa1be5 --- /dev/null +++ b/src/Graphics/include/Graphics/renderer_menu.h @@ -0,0 +1,44 @@ +/** + * @file renderer_menu.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-12-01 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef GRAPHICS_INCLUDE_GRAPHICS_RENDERER_MENU_H_ +#define GRAPHICS_INCLUDE_GRAPHICS_RENDERER_MENU_H_ + +#include "Graphics/renderer_interface.h" +#include "Strike/weapon.h" +#include + +namespace wolfenstein { + +class Menu +{ + public: + Menu(std::shared_ptr context); + ~Menu() = default; + + void Render(); + void ChangeSelection(int direction); + std::shared_ptr GetSelectedWeapon(); + + private: + void RenderBackground(); + void RenderText(const SDL_Color& color); + void RenderWeapon(); + void Animate(); + void ClearScreen(); + std::shared_ptr context_; + std::vector> weapons_; + int selected_weapon_index_ = 0; +}; + +} // namespace wolfenstein + +#endif // GRAPHICS_INCLUDE_GRAPHICS_RENDERER_MENU_H_ diff --git a/src/Graphics/include/Graphics/renderer_result.h b/src/Graphics/include/Graphics/renderer_result.h new file mode 100644 index 0000000..e8a660d --- /dev/null +++ b/src/Graphics/include/Graphics/renderer_result.h @@ -0,0 +1,40 @@ +/** + * @file renderer_result.h + * @author Bilal Kahraman (kahramannbilal@gmail.com) + * @brief + * @version 0.1 + * @date 2024-12-01 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef GRAPHICS_INCLUDE_GRAPHICS_RENDERER_RESULT_H_ +#define GRAPHICS_INCLUDE_GRAPHICS_RENDERER_RESULT_H_ + +#include "Graphics/renderer_interface.h" +#include "TextureManager/texture_manager.h" +#include +#include + +namespace wolfenstein { + +class RendererResult +{ + public: + RendererResult(std::shared_ptr context, Texture texture); + ~RendererResult() = default; + + void Render(); + + private: + void ClearScreen(); + void RenderScreen(); + std::shared_ptr context_; + Texture texture_; + double fade_counter_{0.0}; +}; + +} // namespace wolfenstein + +#endif // GRAPHICS_INCLUDE_GRAPHICS_RENDERER_RESULT_H_ diff --git a/src/Graphics/src/renderer_2d.cpp b/src/Graphics/src/renderer_2d.cpp index 6f3a778..4f5296d 100644 --- a/src/Graphics/src/renderer_2d.cpp +++ b/src/Graphics/src/renderer_2d.cpp @@ -21,13 +21,13 @@ std::vector GenerateCirclePoints(vector2i center, int radius, } // namespace -void Renderer2D::RenderScene(const std::shared_ptr& scene_ptr) { +void Renderer2D::RenderScene() { ClearScreen(); - RenderMap(scene_ptr->GetMap()); - RenderPlayer(scene_ptr->GetPlayer()); - RenderObjects(scene_ptr->GetObjects()); - RenderPaths(scene_ptr->GetEnemies()); - RenderCrosshairs(scene_ptr->GetEnemies()); + RenderMap(scene_->GetMap()); + RenderPlayer(scene_->GetPlayer()); + RenderObjects(scene_->GetObjects()); + RenderPaths(scene_->GetEnemies()); + RenderCrosshairs(scene_->GetEnemies()); SDL_RenderPresent(context_->GetRenderer()); } diff --git a/src/Graphics/src/renderer_3d.cpp b/src/Graphics/src/renderer_3d.cpp index 87d49a9..d57221c 100644 --- a/src/Graphics/src/renderer_3d.cpp +++ b/src/Graphics/src/renderer_3d.cpp @@ -1,17 +1,18 @@ #include "Graphics/renderer_3d.h" #include "Camera/ray.h" #include "TextureManager/texture_manager.h" - +#include namespace wolfenstein { -void Renderer3D::RenderScene(const std::shared_ptr& scene_ptr) { +void Renderer3D::RenderScene() { RenderQueue render_queue(Compare); ClearScreen(); RenderBackground(); - RenderWalls(scene_ptr->GetMap(), render_queue); - RenderObjects(scene_ptr->GetObjects(), render_queue); - RenderWeapon(scene_ptr->GetPlayer(), render_queue); + RenderWalls(scene_->GetMap(), render_queue); + RenderObjects(scene_->GetObjects(), render_queue); + RenderWeapon(scene_->GetPlayer(), render_queue); RenderTextures(render_queue); + RenderHUD(scene_->GetPlayer()); SDL_RenderPresent(context_->GetRenderer()); } @@ -170,6 +171,20 @@ void Renderer3D::RenderWeapon(const std::shared_ptr& player_ptr, config_.height - height_slice, width_slice, height_slice}; render_queue.push({texture_id, src_rect, dest_rect, 0.0}); + + // Check if player is damaged + const auto damage = player_ptr->IsDamaged(); + if (damage.first) { + auto damage_texture = TextureManager::GetInstance().GetTexture(9); + const auto damage_height = damage_texture.height; + const auto damage_width = damage_texture.width; + // change the alpha value of the texture + auto alpha = static_cast(128 - damage.second * 128); + SDL_SetTextureAlphaMod(damage_texture.texture, alpha); + SDL_Rect damage_src_rect{0, 0, damage_width, damage_height}; + SDL_Rect damage_dest_rect{0, 0, config_.width, config_.height}; + render_queue.push({9, damage_src_rect, damage_dest_rect, -1.0}); + } } void Renderer3D::RenderTextures(RenderQueue& render_queue) { @@ -184,4 +199,40 @@ void Renderer3D::RenderTextures(RenderQueue& render_queue) { } } +void Renderer3D::RenderHUD(const std::shared_ptr& player_ptr) { + const auto config_ = context_->GetConfig(); + auto health = static_cast(player_ptr->GetHealth()); + const auto number_textures = + TextureManager::GetInstance().GetTextureCollection("digits"); + + // Split health into digits + std::list digits = {10}; + if (health == 0) { + digits.push_front(0); + } + while (health > 0) { + digits.push_front(health % 10); + health /= 10; + } + int stride = 0; + // Render health top left + for (const auto& d : digits) { + auto digit_texture = + TextureManager::GetInstance().GetTexture(number_textures[d]); + const auto digit_height = digit_texture.height; + const auto digit_width = digit_texture.width; + const double ratio = static_cast(digit_height) / digit_width; + const int width_slice = config_.width / 40; + const int height_slice = width_slice * ratio; + SDL_Rect src_rect = {0, 0, digit_width, digit_height}; + SDL_Rect dest_rect = {config_.width / 40 + stride, + config_.height - height_slice - 10, width_slice, + height_slice}; + SDL_RenderCopy(context_->GetRenderer(), digit_texture.texture, + &src_rect, &dest_rect); + stride += width_slice; + } + +} + } // namespace wolfenstein diff --git a/src/Graphics/src/renderer_interface.cpp b/src/Graphics/src/renderer_interface.cpp index 7e497b2..59e19b8 100644 --- a/src/Graphics/src/renderer_interface.cpp +++ b/src/Graphics/src/renderer_interface.cpp @@ -12,6 +12,18 @@ RendererContext::RendererContext(const std::string& window_name, exit(EXIT_FAILURE); } + if (TTF_Init() != 0) { + SDL_Log("Unable to initialize TTF: %s", SDL_GetError()); + exit(EXIT_FAILURE); + } + + const auto font_path = std::string(RESOURCE_DIR) + "font/EternalAncient.ttf"; + font_ = TTF_OpenFont(font_path.c_str(), 16); // Font size: 24 + if (!font_) { + std::cerr << "Failed to load font: " << TTF_GetError() << std::endl; + exit(EXIT_FAILURE); + } + window_ = SDL_CreateWindow(window_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config_.width, config_.height, SDL_WINDOW_SHOWN); @@ -35,7 +47,9 @@ RendererContext::RendererContext(const std::string& window_name, RendererContext::~RendererContext() { SDL_DestroyRenderer(renderer_); + TTF_CloseFont(font_); SDL_DestroyWindow(window_); + TTF_Quit(); SDL_Quit(); } @@ -43,6 +57,10 @@ SDL_Renderer* RendererContext::GetRenderer() const { return renderer_; } +TTF_Font* RendererContext::GetFont() const { + return font_; +} + SDL_Window* RendererContext::GetWindow() const { return window_; } @@ -63,6 +81,10 @@ void IRenderer::ClearScreen() { SDL_RenderClear(context_->GetRenderer()); } +void IRenderer::SetScene(const std::shared_ptr& scene_ptr) { + scene_ = scene_ptr; +} + std::shared_ptr IRenderer::GetContext() const { return context_; } diff --git a/src/Graphics/src/renderer_menu.cpp b/src/Graphics/src/renderer_menu.cpp new file mode 100644 index 0000000..afcb55b --- /dev/null +++ b/src/Graphics/src/renderer_menu.cpp @@ -0,0 +1,137 @@ +#include "Graphics/renderer_menu.h" +#include "Math/vector.h" +#include "State/weapon_state.h" +#include "TextureManager/texture_manager.h" +#include "TimeManager/time_manager.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace wolfenstein { + +Menu::Menu(std::shared_ptr context) : context_(context) { + std::vector weapon_names = {"mp5", "shotgun"}; + for (const auto& w : weapon_names) { + WeaponStatePtr loaded_state = std::make_shared(); + weapons_.push_back(std::make_shared(w)); + weapons_.back()->TransitionTo(loaded_state); + } +} + +void Menu::Render() { + Animate(); + ClearScreen(); + RenderBackground(); + RenderWeapon(); + + SDL_Color textColor = {255, 255, 255, 255}; // White text + + RenderText(textColor); + + SDL_RenderPresent(context_->GetRenderer()); +} + +void Menu::RenderText(const SDL_Color& color) { + SDL_Surface* textSurface = TTF_RenderText_Solid( + context_->GetFont(), "Hello Comrade, Choose your weapon below", color); + if (!textSurface) { + std::cerr << "Failed to create text surface: " << TTF_GetError() + << std::endl; + exit(EXIT_FAILURE); + } + SDL_Texture* textTexture = + SDL_CreateTextureFromSurface(context_->GetRenderer(), textSurface); + if (!textTexture) { + std::cerr << "Failed to create texture: " << SDL_GetError() + << std::endl; + } + SDL_FreeSurface( + textSurface); // Free the surface after creating the texture + const double ratio = static_cast(textSurface->h) / textSurface->w; + const int width_slice = context_->GetConfig().width / 2.6; + const int height_slice = width_slice * ratio; + SDL_Rect rect = {(context_->GetConfig().width / 2) + (-width_slice / 2), + (context_->GetConfig().height / 2) + + (-context_->GetConfig().height / 3), + width_slice, height_slice}; // Position and size + SDL_RenderCopy(context_->GetRenderer(), textTexture, nullptr, &rect); + SDL_DestroyTexture(textTexture); + + SDL_Surface* textSurface2 = TTF_RenderText_Solid( + context_->GetFont(), "Use <-, -> and space for selection", color); + if (!textSurface2) { + std::cerr << "Failed to create text surface: " << TTF_GetError() + << std::endl; + exit(EXIT_FAILURE); + } + SDL_Texture* textTexture2 = + SDL_CreateTextureFromSurface(context_->GetRenderer(), textSurface2); + if (!textTexture2) { + std::cerr << "Failed to create texture: " << SDL_GetError() + << std::endl; + } + SDL_FreeSurface( + textSurface2); // Free the surface after creating the texture + const double ratio_2 = + static_cast(textSurface2->h) / textSurface2->w; + const int width_slice_2 = context_->GetConfig().width / 2.6; + const int height_slice_2 = width_slice_2 * ratio_2; + SDL_Rect rect2 = {(context_->GetConfig().width / 2) + (-width_slice_2 / 2), + (context_->GetConfig().height / 2) + + (context_->GetConfig().height / 12), + width_slice_2, height_slice_2}; // Position and size + SDL_RenderCopy(context_->GetRenderer(), textTexture2, nullptr, &rect2); + SDL_DestroyTexture(textTexture2); +} + +void Menu::RenderWeapon() { + const auto id = weapons_[selected_weapon_index_]->GetTextureId(); + const auto texture = TextureManager::GetInstance().GetTexture(id); + const double ratio = static_cast(texture.height) / texture.width; + const int width_slice = context_->GetConfig().width / 2.6; + const int height_slice = width_slice * ratio; + SDL_Rect src_rect = {0, 0, width_slice, height_slice}; + SDL_Rect dest_rect = {context_->GetConfig().width / 2 - width_slice / 2 - context_->GetConfig().width/20, + context_->GetConfig().height / 2 - height_slice / 2 - + context_->GetConfig().height / 8, + width_slice, height_slice}; + SDL_RenderCopy(context_->GetRenderer(), texture.texture, &src_rect, + &dest_rect); +} + +void Menu::Animate() { + weapons_[selected_weapon_index_]->Update( + TimeManager::GetInstance().GetDeltaTime()); +} + +void Menu::ChangeSelection(int direction) { + selected_weapon_index_ += direction; + selected_weapon_index_ %= weapons_.size(); + weapons_[selected_weapon_index_]->Reload(); +} + +std::shared_ptr Menu::GetSelectedWeapon() { + WeaponStatePtr state = std::make_shared(); + weapons_[selected_weapon_index_]->TransitionTo(state); + return weapons_[selected_weapon_index_]; +} + +void Menu::RenderBackground() { + const auto config = context_->GetConfig(); + SDL_Texture* backgroundTexture = + TextureManager::GetInstance().GetTexture(8).texture; + SDL_Rect rect = {0, 0, config.width, config.height}; + SDL_RenderCopy(context_->GetRenderer(), backgroundTexture, nullptr, &rect); +} + +void Menu::ClearScreen() { + SDL_SetRenderDrawColor(context_->GetRenderer(), 0, 0, 0, 255); + SDL_RenderClear(context_->GetRenderer()); +} + +} // namespace wolfenstein diff --git a/src/Graphics/src/renderer_result.cpp b/src/Graphics/src/renderer_result.cpp new file mode 100644 index 0000000..2e0d6ef --- /dev/null +++ b/src/Graphics/src/renderer_result.cpp @@ -0,0 +1,37 @@ +#include "Graphics/renderer_result.h" +#include "TextureManager/texture_manager.h" +#include "TimeManager/time_manager.h" +#include + +namespace wolfenstein { + +RendererResult::RendererResult(std::shared_ptr context, + Texture texture) + : context_(context), texture_(texture) {} + +void RendererResult::Render() { + ClearScreen(); + RenderScreen(); + SDL_RenderPresent(context_->GetRenderer()); +} + +void RendererResult::RenderScreen() { + fade_counter_ += TimeManager::GetInstance().GetDeltaTime() / 5.0; + if (fade_counter_ >= 1.0) { + fade_counter_ = 1.0; + } + SDL_SetTextureAlphaMod(texture_.texture, + static_cast(fade_counter_ * 255)); + SDL_Rect src_rect = {0, 0, texture_.width, texture_.height}; + SDL_Rect dest_rect = {0, 0, context_->GetConfig().width, + context_->GetConfig().height}; + SDL_RenderCopy(context_->GetRenderer(), texture_.texture, &src_rect, + &dest_rect); +} + +void RendererResult::ClearScreen() { + SDL_SetRenderDrawColor(context_->GetRenderer(), 0, 0, 0, 255); + SDL_RenderClear(context_->GetRenderer()); +} + +} // namespace wolfenstein diff --git a/src/Map/src/map.cpp b/src/Map/src/map.cpp index b553d5e..b734f2a 100644 --- a/src/Map/src/map.cpp +++ b/src/Map/src/map.cpp @@ -77,8 +77,8 @@ void Map::MapToPathFinderMap() { for (uint16_t i = 0; i < size_x_; i++) { for (uint16_t j = 0; j < size_y_; j++) { if (map_[i][j] == 0) { - for (uint16_t k = 0; k < (1 / res) ; k++) { - for (uint16_t l = 0; l < (1 / res) ; l++) { + for (uint16_t k = 0; k < (1 / res); k++) { + for (uint16_t l = 0; l < (1 / res); l++) { path_finder_map_->SetNodeState( planning::Node(i / res + k, j / res + l), planning::NodeState::kFree); diff --git a/src/State/src/enemy_state.cpp b/src/State/src/enemy_state.cpp index 7b1727b..f32543b 100644 --- a/src/State/src/enemy_state.cpp +++ b/src/State/src/enemy_state.cpp @@ -180,13 +180,11 @@ void DeathState::Update(const double& delta_time) { } } - void DeathState::OnContextSet() { animation_ = std::make_unique( context_->GetBotName() + "_death", animation_speed_); } - EnemyStateType DeathState::GetType() const { return EnemyStateType::Death; } diff --git a/src/TextureManager/include/TextureManager/texture_manager.h b/src/TextureManager/include/TextureManager/texture_manager.h index dd5dabd..c349b84 100644 --- a/src/TextureManager/include/TextureManager/texture_manager.h +++ b/src/TextureManager/include/TextureManager/texture_manager.h @@ -38,7 +38,7 @@ class TextureManager TextureManager(const TextureManager&) = delete; TextureManager& operator=(const TextureManager&) = delete; - ~TextureManager() = default; + ~TextureManager(); void InitManager(SDL_Renderer* renderer); diff --git a/src/TextureManager/src/texture_manager.cpp b/src/TextureManager/src/texture_manager.cpp index f7eef0d..0161c8b 100644 --- a/src/TextureManager/src/texture_manager.cpp +++ b/src/TextureManager/src/texture_manager.cpp @@ -13,6 +13,12 @@ TextureManager& TextureManager::GetInstance() { return *instance_; } +TextureManager::~TextureManager() { + for (auto& texture : textures_) { + SDL_DestroyTexture(texture.second.texture); + } +} + void TextureManager::InitManager(SDL_Renderer* renderer) { renderer_ = renderer; t_count_ = 0; @@ -52,7 +58,10 @@ void TextureManager::LoadStaticTextures() { LoadTexture(t_count_++, texture_path + "5.png"); LoadTexture(t_count_++, texture_path + "crosshair.png"); LoadTexture(t_count_++, texture_path + "solid_black.png"); - + LoadTexture(t_count_++, texture_path + "menu_background.png"); + LoadTexture(t_count_++, texture_path + "damage_taken.png"); + LoadTexture(t_count_++, texture_path + "game_over.png"); + LoadTexture(t_count_++, texture_path + "win.png"); // Digits auto begin = t_count_; LoadTexture(t_count_++, texture_path + "digits/0.png");