From 54e8c75797ee97acbe8c2c2824c70e888da5f60a Mon Sep 17 00:00:00 2001 From: Bilal Kahraman Date: Sun, 11 Aug 2024 11:52:38 +0300 Subject: [PATCH] Render static object in game --- src/Camera/include/Camera/camera.h | 7 +- src/Camera/include/Camera/raycaster.h | 5 +- src/Camera/src/camera.cpp | 50 +++- src/Camera/src/raycaster.cpp | 13 +- src/Characters/src/player.cpp | 12 +- src/Core/src/game.cpp | 12 +- src/GameObjects/CMakeLists.txt | 1 - .../include/GameObjects/static_object.h | 10 +- src/GameObjects/src/game_object.cpp | 6 - src/GameObjects/src/static_object.cpp | 6 +- src/Graphics/include/Graphics/renderer.h | 18 +- src/Graphics/src/renderer.cpp | 246 +++++++++++++++--- src/Math/include/Math/vector.h | 26 +- src/Math/src/vector.cpp | 61 ++++- src/TextureManager/src/texture_manager.cpp | 4 + .../include/TimeManager/time_manager.h | 2 +- src/TimeManager/src/time_manager.cpp | 2 +- 17 files changed, 398 insertions(+), 83 deletions(-) delete mode 100644 src/GameObjects/src/game_object.cpp diff --git a/src/Camera/include/Camera/camera.h b/src/Camera/include/Camera/camera.h index 0b94d90..a773f35 100644 --- a/src/Camera/include/Camera/camera.h +++ b/src/Camera/include/Camera/camera.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,13 @@ class Camera2D std::shared_ptr GetRays() const; std::shared_ptr GetCrosshairRay() const; Position2D GetPosition() const; - double GetFov() const { return config_.fov; } - double GetDeltaAngle() const { return config_.fov / config_.width; } + double GetFov() const; + double GetDeltaAngle() const; void SetPosition(const Position2D& position); + Ray CalculateObjectRay(const std::shared_ptr& object) const; + private: void InitRays(); Camera2DConfig config_; diff --git a/src/Camera/include/Camera/raycaster.h b/src/Camera/include/Camera/raycaster.h index 0dcdcec..9e07f32 100644 --- a/src/Camera/include/Camera/raycaster.h +++ b/src/Camera/include/Camera/raycaster.h @@ -23,7 +23,7 @@ namespace wolfenstein { class RayCaster { public: - RayCaster(const int width, const double fov, const double depth); + RayCaster(const int num_ray, const double fov, const double depth); ~RayCaster(); void Update(const std::shared_ptr& map_ptr, const Position2D& position, @@ -31,13 +31,14 @@ class RayCaster Ray Cast(const std::shared_ptr& map_ptr, const Position2D& position, const double ray_theta); + double GetDeltaTheta() const; private: void PrepareRay(const Position2D& position, const double ray_angle, Ray& ray, vector2d& ray_unit_step, vector2d& ray_length_1d, vector2i& step, vector2i& map_check); - int width_; + int num_ray_; double fov_; double depth_; double delta_theta_; diff --git a/src/Camera/src/camera.cpp b/src/Camera/src/camera.cpp index 663cf25..c6670f6 100644 --- a/src/Camera/src/camera.cpp +++ b/src/Camera/src/camera.cpp @@ -10,19 +10,21 @@ */ #include "Camera/camera.h" +#include "Math/vector.h" +#include namespace wolfenstein { Camera2D::Camera2D(const Camera2DConfig& config) : config_(config), - ray_cast_( - std::make_shared(config.width, config.fov, config.depth)) { + ray_cast_(std::make_shared(config.width / 2, config.fov, + config.depth)) { InitRays(); } void Camera2D::Update(const std::shared_ptr& map_ptr) { ray_cast_->Update(map_ptr, position_, rays_); - crosshair_ray_ = std::make_shared(rays_->at(config_.width / 2)); + crosshair_ray_ = std::make_shared(rays_->at(config_.width / 4)); } std::shared_ptr Camera2D::GetRays() const { @@ -37,13 +39,53 @@ Position2D Camera2D::GetPosition() const { return position_; } +double Camera2D::GetFov() const { + return config_.fov; +} +double Camera2D::GetDeltaAngle() const { + return ray_cast_->GetDeltaTheta(); +} + void Camera2D::SetPosition(const Position2D& position) { position_ = position; } +Ray Camera2D::CalculateObjectRay( + const std::shared_ptr& object) const { + Ray object_ray{}; + auto static_object = std::dynamic_pointer_cast(object); + const auto object_pose = static_object->GetPose(); + const auto w = static_object->GetWidth(); + + // check if object is in the camera view + auto object_distance = Distance(object_pose, position_.pose); + if (object_distance > config_.depth) { + return object_ray; + } + + const auto object_center_angle = std::atan2( + object_pose.y - position_.pose.y, object_pose.x - position_.pose.x); + + auto object_left_edge_angle = + SubRadian(object_center_angle, ToRadians(90.0)); + const auto left_edge_point = + object_pose + vector2d{w * std::cos(object_left_edge_angle), + w * std::sin(object_left_edge_angle)}; + const auto left_edge_angle = + std::atan2(left_edge_point.y - position_.pose.y, + left_edge_point.x - position_.pose.x); + object_ray.theta = + left_edge_angle > 0 ? left_edge_angle : 2 * M_PI + left_edge_angle; + object_ray.is_hit = true; + object_ray.perpendicular_distance = object_distance; + object_ray.wall_id = static_object->GetTextureId(); + + return object_ray; +} + void Camera2D::InitRays() { rays_ = std::make_shared(); - for (int i = 0; i < config_.width; i++) { + for (int i = 0; i < config_.width / 2; i++) { rays_->emplace_back(Ray()); } } diff --git a/src/Camera/src/raycaster.cpp b/src/Camera/src/raycaster.cpp index 1dce421..45dc0c1 100644 --- a/src/Camera/src/raycaster.cpp +++ b/src/Camera/src/raycaster.cpp @@ -4,10 +4,11 @@ namespace wolfenstein { -RayCaster::RayCaster(const int width, const double fov, const double depth) - : width_(width), fov_(fov), depth_(depth) { - delta_theta_ = fov_ / width_; -} +RayCaster::RayCaster(const int num_ray, const double fov, const double depth) + : num_ray_(num_ray), + fov_(fov), + depth_(depth), + delta_theta_(fov_ / num_ray) {} RayCaster::~RayCaster() {} @@ -61,6 +62,10 @@ Ray RayCaster::Cast(const std::shared_ptr& map_ptr, return ray; } +double RayCaster::GetDeltaTheta() const { + return delta_theta_; +} + void RayCaster::PrepareRay(const Position2D& position, const double ray_theta, Ray& ray, vector2d& ray_unit_step, vector2d& ray_length_1d, vector2i& step, diff --git a/src/Characters/src/player.cpp b/src/Characters/src/player.cpp index 143b4ee..e40fe20 100644 --- a/src/Characters/src/player.cpp +++ b/src/Characters/src/player.cpp @@ -1,5 +1,6 @@ #include "Characters/player.h" #include "CollisionManager/collision_manager.h" +#include "Math/vector.h" #include namespace wolfenstein { @@ -52,14 +53,14 @@ void Player::Move(double delta_time) { } if (keystate[SDL_SCANCODE_A]) { delta_movement.first += speed_sin; - delta_movement.second += -speed_cos; + delta_movement.second -= speed_cos; } if (keystate[SDL_SCANCODE_S]) { - delta_movement.first += -speed_cos; - delta_movement.second += -speed_sin; + delta_movement.first -= speed_cos; + delta_movement.second -= speed_sin; } if (keystate[SDL_SCANCODE_D]) { - delta_movement.first += -speed_sin; + delta_movement.first -= speed_sin; delta_movement.second += speed_cos; } if (!CollisionManager::GetInstance().CheckWallCollision( @@ -76,9 +77,8 @@ void Player::Rotate(double delta_time) { if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE) { int x, y; SDL_GetMouseState(&x, &y); - position_.theta += (x - 400) * 0.001; + position_.theta = SumRadian(position_.theta, (x - 400) * 0.001); SDL_WarpMouseInWindow(nullptr, 400, 300); - position_.theta = std::fmod(position_.theta, (M_PI * 2)); } } diff --git a/src/Core/src/game.cpp b/src/Core/src/game.cpp index 75dc627..c4a9b3d 100644 --- a/src/Core/src/game.cpp +++ b/src/Core/src/game.cpp @@ -30,7 +30,7 @@ void Game::Init() { config_.fov, false}; renderer_ = std::make_shared("Wolfenstein", render_config); - Camera2DConfig camera_config = {config_.screen_width / 2, config_.fov, + Camera2DConfig camera_config = {config_.screen_width, config_.fov, config_.view_distance}; camera_ = std::make_shared(camera_config); @@ -43,11 +43,17 @@ void Game::Init() { player_->SetCameraPositionUpdator( std::bind(camera_position_updator, std::placeholders::_1)); - std::shared_ptr candlebra = - std::make_shared(vector2d(3.5, 1.5), 6, 0.1, 0.1); + const auto candlebra = + std::make_shared(vector2d(3.5, 1.5), 6, 0.2, 0.2); + const auto candlebra1 = + std::make_shared(vector2d(12.5, 9.5), 8, 0.2, 0.2); + const auto candlebra2 = + std::make_shared(vector2d(3.5, 7.5), 6, 0.2, 0.2); scene_->AddObject(player_); scene_->AddObject(candlebra); + scene_->AddObject(candlebra1); + scene_->AddObject(candlebra2); is_running_ = true; time_manager_->InitClock(); diff --git a/src/GameObjects/CMakeLists.txt b/src/GameObjects/CMakeLists.txt index 76552c7..d11d7a3 100644 --- a/src/GameObjects/CMakeLists.txt +++ b/src/GameObjects/CMakeLists.txt @@ -7,7 +7,6 @@ link_directories( add_library( game_object STATIC - src/game_object.cpp src/static_object.cpp src/dynamic_object.cpp ) diff --git a/src/GameObjects/include/GameObjects/static_object.h b/src/GameObjects/include/GameObjects/static_object.h index 22a44b1..b6fb279 100644 --- a/src/GameObjects/include/GameObjects/static_object.h +++ b/src/GameObjects/include/GameObjects/static_object.h @@ -22,7 +22,7 @@ class StaticObject : public IGameObject { public: explicit StaticObject(const vector2d& pose_, const int texture_id_, - const int width_, const int height_); + const double width_, const double height_); ~StaticObject(); void Update(double delta_time) override; @@ -34,14 +34,14 @@ class StaticObject : public IGameObject vector2d GetPose() const override; int GetTextureId() const; - int GetWidth() const; - int GetHeight() const; + double GetWidth() const; + double GetHeight() const; protected: vector2d pose; int texture_id; - int width; - int height; + double width; + double height; }; } // namespace wolfenstein diff --git a/src/GameObjects/src/game_object.cpp b/src/GameObjects/src/game_object.cpp deleted file mode 100644 index 9fd4711..0000000 --- a/src/GameObjects/src/game_object.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "GameObjects/game_object.h" - -namespace wolfenstein { - - -} // namespace wolfenstein diff --git a/src/GameObjects/src/static_object.cpp b/src/GameObjects/src/static_object.cpp index 8c6a5c2..981b482 100644 --- a/src/GameObjects/src/static_object.cpp +++ b/src/GameObjects/src/static_object.cpp @@ -4,7 +4,7 @@ namespace wolfenstein { StaticObject::StaticObject(const vector2d& pose_, const int texture_id_, - const int width_, const int height_) + const double width_, const double height_) : pose(pose_), texture_id(texture_id_), width(width_), height(height_) {} StaticObject::~StaticObject() {} @@ -33,10 +33,10 @@ vector2d StaticObject::GetPose() const { int StaticObject::GetTextureId() const { return texture_id; } -int StaticObject::GetWidth() const { +double StaticObject::GetWidth() const { return width; } -int StaticObject::GetHeight() const { +double StaticObject::GetHeight() const { return height; } diff --git a/src/Graphics/include/Graphics/renderer.h b/src/Graphics/include/Graphics/renderer.h index 4f9c3f4..878c1ff 100644 --- a/src/Graphics/include/Graphics/renderer.h +++ b/src/Graphics/include/Graphics/renderer.h @@ -12,15 +12,14 @@ #ifndef GRAPHICS_RENDERER_H_ #define GRAPHICS_RENDERER_H_ -#include "GameObjects/dynamic_object.h" #include "GameObjects/game_object.h" -#include "GameObjects/static_object.h" #include "scene.h" #include #include #include #include #include +#include #include namespace wolfenstein { @@ -74,6 +73,9 @@ class Renderer void RenderScene(const std::shared_ptr& scene_ptr, const std::shared_ptr& camera_ptr); + void RenderScene2D(const std::shared_ptr& scene_ptr, + const std::shared_ptr& camera_ptr); + private: void RenderBackground(); void RenderWalls(const std::shared_ptr& map_ptr, @@ -87,9 +89,19 @@ class Renderer void RenderObjects(const std::vector>& objects, const std::shared_ptr& camera_ptr, RenderQueue& render_queue); - + int CalculateHorizontalSlice(const Ray& ray, + const std::shared_ptr camera_ptr); + std::tuple CalculateVerticalSlice(const double& distance); void RenderTextures(RenderQueue& render_queue); + + // Render 2D void ClearScreen(); + void SetDrawColor(SDL_Color color); + void DrawFilledRectangle(vector2i start, vector2i end); + void RenderMap(const std::shared_ptr map_ptr); + void RenderObjects(const std::vector>& objects, + const std::shared_ptr camera_ptr); + void DrawLine(vector2i start, vector2i end); SDL_Renderer* renderer_; SDL_Window* window_; diff --git a/src/Graphics/src/renderer.cpp b/src/Graphics/src/renderer.cpp index 39df0a2..78e03f0 100644 --- a/src/Graphics/src/renderer.cpp +++ b/src/Graphics/src/renderer.cpp @@ -1,14 +1,35 @@ #include "Graphics/renderer.h" +#include "Camera/ray.h" #include "GameObjects/static_object.h" #include "Map/map.h" #include "Math/vector.h" +#include #include #include #include +#include #include - +#include namespace wolfenstein { +namespace { +std::vector GenerateCirclePoints(vector2i center, int radius, + int num_points) { + const double increment = 2 * M_PI / num_points; + + std::vector points; + for (int i = 0; i < num_points; ++i) { + double angle = i * increment; + int x = static_cast(center.x + radius * std::cos(angle)); + int y = static_cast(center.y + radius * std::sin(angle)); + points.push_back({x, y}); + } + + return points; +} + +} // namespace + Renderer::Renderer(const std::string& window_name, const RenderConfig& config) : config_(config) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { @@ -46,7 +67,7 @@ Renderer::~Renderer() { void Renderer::RenderScene(const std::shared_ptr& scene_ptr, const std::shared_ptr& camera_ptr) { RenderQueue render_queue(Compare); - // ClearScreen(); + ClearScreen(); RenderBackground(); RenderWalls(scene_ptr->GetMap(), camera_ptr, render_queue); RenderObjects(scene_ptr->GetObjects(), camera_ptr, render_queue); @@ -88,11 +109,10 @@ void Renderer::RenderWalls(const std::shared_ptr& map_ptr, void Renderer::RenderIfRayHit(const int horizontal_slice, const Ray& ray, const std::shared_ptr& camera_ptr, RenderQueue& render_queue) { - auto distance = ray.perpendicular_distance * - std::cos(camera_ptr->GetPosition().theta - ray.theta); - auto line_height = static_cast(config_.height / distance); - int draw_start = -line_height / 2 + config_.height / 2; - int draw_end = line_height / 2 + config_.height / 2; + const auto distance = ray.perpendicular_distance * + std::cos(camera_ptr->GetPosition().theta - ray.theta); + const auto [line_height, draw_start, draw_end] = + CalculateVerticalSlice(distance); auto hit_point = ray.is_hit_vertical ? ray.hit_point.y : ray.hit_point.x; hit_point = std::fmod(hit_point, 1.0); @@ -101,22 +121,18 @@ void Renderer::RenderIfRayHit(const int horizontal_slice, const Ray& ray, int texture_point = static_cast(hit_point * texture_height); SDL_Rect src_rect = {texture_point, 0, 2, texture_height}; - SDL_Rect dest_rect = {horizontal_slice, draw_start, 2, - draw_end - draw_start}; + SDL_Rect dest_rect = {horizontal_slice, draw_start, 2, line_height}; render_queue.push({ray.wall_id, src_rect, dest_rect, distance}); } void Renderer::RenderIfRayHitNot(const int horizontal_slice, RenderQueue& render_queue) { - auto line_height = - static_cast(config_.height / (config_.view_distance + 0.5)); - int draw_start = -line_height / 2 + config_.height / 2; - int draw_end = line_height / 2 + config_.height / 2; + const auto [line_height, draw_start, draw_end] = + CalculateVerticalSlice(config_.view_distance); SDL_Rect src_rect = {0, 0, 2, TextureManager::GetInstance().GetTexture(7).height}; - SDL_Rect dest_rect = {horizontal_slice, draw_start, 2, - draw_end - draw_start}; + SDL_Rect dest_rect = {horizontal_slice, draw_start, 2, line_height}; render_queue.push({7, src_rect, dest_rect, config_.view_distance}); } @@ -125,38 +141,64 @@ void Renderer::RenderObjects( const std::shared_ptr& camera_ptr, RenderQueue& render_queue) { for (const auto& object : objects) { if (object->GetObjectType() == ObjectType::STATIC_OBJECT) { - auto static_object = + const auto static_object = std::dynamic_pointer_cast(object); - auto object_position = static_object->GetPose(); - auto camera_position = camera_ptr->GetPosition(); - - // check if object is in the camera view - auto object_distance = - Distance(object_position, camera_position.pose); - if (object_distance > config_.view_distance) { + const auto object_ray = camera_ptr->CalculateObjectRay(object); + if (!object_ray.is_hit) { continue; } - // check if object is in the camera fov - auto object_angle = - std::atan2(object_position.y - camera_position.pose.y, - object_position.x - camera_position.pose.x); + const auto w = static_object->GetWidth(); - auto angle_diff = std::abs(camera_position.theta - object_angle); - if (angle_diff > config_.fov / 2 + +0.174532925) { - continue; - } - auto src_rect = SDL_Rect{0, 0, 897, 1921}; - auto dest_rect = SDL_Rect{ - static_cast(object_position.x * config_.scale), - static_cast(object_position.y * config_.scale), 200, 200}; - render_queue.push({static_object->GetTextureId(), src_rect, - dest_rect, object_distance}); + const auto [line_height, draw_start, draw_end] = + CalculateVerticalSlice(object_ray.perpendicular_distance); + + SDL_Rect src_rect = {0, 0, + TextureManager::GetInstance() + .GetTexture(object_ray.wall_id) + .width, + TextureManager::GetInstance() + .GetTexture(object_ray.wall_id) + .height}; + const auto horizontal_slice = + CalculateHorizontalSlice(object_ray, camera_ptr); + + SDL_Rect dest_rect = {horizontal_slice, draw_start, + static_cast(w * line_height), + line_height}; + render_queue.push({object_ray.wall_id, src_rect, dest_rect, + object_ray.perpendicular_distance}); } } } +int Renderer::CalculateHorizontalSlice( + const Ray& ray, const std::shared_ptr camera_ptr) { + auto cam_theta = camera_ptr->GetPosition().theta; + const auto vector_of_crosshair = + vector2d{std::cos(cam_theta), std::sin(cam_theta)}; + const auto vector_of_ray = + vector2d{std::cos(ray.theta), std::sin(ray.theta)}; + + const auto angle_between = CalculateAngleBetweenTwoVectorsSigned( + vector_of_ray, vector_of_crosshair); + + const auto horizontal_slice = + static_cast(angle_between / camera_ptr->GetDeltaAngle()) * 2 + + config_.width / 2; + + return horizontal_slice; +} + +std::tuple Renderer::CalculateVerticalSlice( + const double& distance) { + auto line_height = static_cast(config_.height / distance); + int draw_start = -line_height / 2 + config_.height / 2; + int draw_end = line_height / 2 + config_.height / 2; + return std::make_tuple(line_height, draw_start, draw_end); +} + void Renderer::RenderTextures(RenderQueue& render_queue) { while (!render_queue.empty()) { auto renderable_texture = render_queue.top(); @@ -173,4 +215,134 @@ void Renderer::ClearScreen() { SDL_RenderClear(renderer_); } +void Renderer::RenderScene2D(const std::shared_ptr& scene_ptr, + const std::shared_ptr& camera_ptr) { + camera_ptr->Update(scene_ptr->GetMap()); + ClearScreen(); + RenderMap(scene_ptr->GetMap()); + RenderObjects(scene_ptr->GetObjects(), camera_ptr); + SDL_RenderPresent(renderer_); +} + +void Renderer::RenderObjects( + const std::vector>& objects, + const std::shared_ptr camera_ptr) { + + for (const auto& object : objects) { + if (object->GetObjectType() == ObjectType::CHARACTER_PLAYER) { + auto player = std::dynamic_pointer_cast(object); + const auto position = player->GetPosition(); + const auto crosshair_ray = camera_ptr->GetCrosshairRay(); + + SetDrawColor({0xFF, 0xA5, 0, 255}); + const auto rays = camera_ptr->GetRays(); + const auto first_ray = rays->front(); + const auto start = ToVector2i(position.pose * config_.scale); + const auto end = ToVector2i((first_ray.hit_point) * config_.scale); + DrawLine(start, end); + + const auto last_ray = rays->back(); + const auto start_last = ToVector2i(position.pose * config_.scale); + const auto end_last = + ToVector2i((last_ray.hit_point) * config_.scale); + DrawLine(start_last, end_last); + SetDrawColor({255, 0, 0, 255}); + const auto circle_points = GenerateCirclePoints( + ToVector2i(position.pose * config_.scale), 10, 20); + for (unsigned int i = 0; i < circle_points.size(); i++) { + SDL_RenderDrawPoint(renderer_, circle_points[i].x, + circle_points[i].y); + } + DrawLine(ToVector2i(position.pose * config_.scale), + ToVector2i((crosshair_ray->origin + + crosshair_ray->direction * 10) * + config_.scale)); + } + + if (object->GetObjectType() == ObjectType::STATIC_OBJECT) { + const auto object_ray = camera_ptr->CalculateObjectRay(object); + if (!object_ray.is_hit) { + continue; + } + auto cam_theta = camera_ptr->GetPosition().theta; + const auto vector_of_crosshair = + vector2d{std::cos(cam_theta), std::sin(cam_theta)}; + const auto vector_of_ray = vector2d{std::cos(object_ray.theta), + std::sin(object_ray.theta)}; + + const auto angle_between = CalculateAngleBetweenTwoVectorsSigned( + vector_of_ray, vector_of_crosshair); + if (std::abs(angle_between) > ToRadians(45.0)) { + continue; + } + + auto static_object = + std::dynamic_pointer_cast(object); + SetDrawColor({0xFF, 0xA5, 0, 255}); + const auto object_pose = static_object->GetPose(); + const auto w = static_object->GetWidth(); + + const auto object_points = GenerateCirclePoints( + ToVector2i(object_pose * config_.scale), 10, 20); + for (unsigned int i = 0; i < object_points.size(); i++) { + SDL_RenderDrawPoint(renderer_, object_points[i].x, + object_points[i].y); + } + + const auto object_angle = + std::atan2(object_pose.y - camera_ptr->GetPosition().pose.y, + object_pose.x - camera_ptr->GetPosition().pose.x); + + const auto to_left = SubRadian(object_angle, ToRadians(90.0)); + const auto to_right = SumRadian(object_angle, ToRadians(90.0)); + const auto left_vertex = + object_pose + + vector2d{w * std::cos(to_left), w * std::sin(to_left)}; + const auto right_vertex = + object_pose + + vector2d{w * std::cos(to_right), w * std::sin(to_right)}; + DrawLine(ToVector2i(left_vertex * config_.scale), + ToVector2i(right_vertex * config_.scale)); + const auto left_point = GenerateCirclePoints( + ToVector2i(left_vertex * config_.scale), 5, 20); + for (unsigned int i = 0; i < left_point.size(); i++) { + SDL_RenderDrawPoint(renderer_, left_point[i].x, + left_point[i].y); + } + } + } +} + +void Renderer::DrawLine(vector2i start, vector2i end) { + SDL_RenderDrawLine(renderer_, start.x, start.y, end.x, end.y); +} + +void Renderer::RenderMap(const std::shared_ptr map_ptr) { + + const auto& map = map_ptr->GetMap(); + const auto& size_x = map_ptr->GetSizeX(); + const auto& size_y = map_ptr->GetSizeY(); + + SetDrawColor({162, 117, 76, 255}); + + for (int i = 0; i < size_x; i++) { + for (int j = 0; j < size_y; j++) { + if (map[i][j] != 0) { + DrawFilledRectangle( + {config_.scale * i, config_.scale * j}, + {config_.scale * (i + 1), config_.scale * (j + 1)}); + } + } + } +} + +void Renderer::SetDrawColor(SDL_Color color) { + SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, color.a); +} + +void Renderer::DrawFilledRectangle(vector2i start, vector2i end) { + SDL_Rect rect{start.x, start.y, end.x - start.x, end.y - start.y}; + SDL_RenderFillRect(renderer_, &rect); +} + } // namespace wolfenstein diff --git a/src/Math/include/Math/vector.h b/src/Math/include/Math/vector.h index 1d27017..25bd86e 100644 --- a/src/Math/include/Math/vector.h +++ b/src/Math/include/Math/vector.h @@ -55,8 +55,9 @@ struct vector2d vector2d Cross(const vector2d& v) const; double Dot(const vector2d& v) const; - void Norm(); double Magnitude() const; + double Determinant(const vector2d& v) const; + void Norm(); }; // To convert vector2d to vector2i @@ -71,6 +72,18 @@ std::ostream& operator<<(std::ostream& out, const vector2i& v); // ostream operator for vector2i std::ostream& operator<<(std::ostream& out, const vector2d& v); +// SumRadian calculates the sum of two radian values +double SumRadian(const double radian1, const double radian2); + +// SubRadian calculates the subtraction of two radian values +double SubRadian(const double radian1, const double radian2); + +// SumDegree calculates the sum of two degree values +double SumDegree(const double degree1, const double degree2); + +// SubDegree calculates the subtraction of two degree values +double SubDegree(const double degree1, const double degree2); + // ToRadians converts degree to radians double ToRadians(const double degree); @@ -83,6 +96,17 @@ double Distance(const vector2d& v1, const vector2d& v2); // Distance calculates the distance between two points double Distance(const vector2i& v1, const vector2i& v2); +// CalculateAngleBetweenTwoVectors calculates the angle between two vectors +double CalculateAngleBetweenTwoVectors(const vector2d& v1, const vector2d& v2); + +// CalculateAngleBetweenTwoVectorsSigned calculates the signed angle between two vectors +double CalculateAngleBetweenTwoVectorsSigned(const vector2d& v1, + const vector2d& v2); + +double CalculateAngleBetweenThreeVectorsSigned(const vector2d& v1, + const vector2d& v2, + const vector2d& v3); + } // namespace wolfenstein #endif // MATH_INCLUDE_VECTOR_H_ diff --git a/src/Math/src/vector.cpp b/src/Math/src/vector.cpp index 2078ac0..d6e3637 100644 --- a/src/Math/src/vector.cpp +++ b/src/Math/src/vector.cpp @@ -113,16 +113,20 @@ double vector2d::Dot(const vector2d& v) const { return x * v.x + y * v.y; } +double vector2d::Magnitude() const { + return std::sqrt(x * x + y * y); +} + +double vector2d::Determinant(const vector2d& v) const { + return x * v.y - y * v.x; +} + void vector2d::Norm() { double size = std::sqrt(x * x + y * y); x /= size; y /= size; } -double vector2d::Magnitude() const { - return std::sqrt(x * x + y * y); -} - vector2i ToVector2i(const vector2d& v) { return {static_cast(v.x), static_cast(v.y)}; } @@ -141,6 +145,22 @@ std::ostream& operator<<(std::ostream& out, const vector2d& v) { return out; } +double SumRadian(const double radian1, const double radian2) { + return std::fmod(radian1 + radian2, (M_PI * 2)); +} + +double SubRadian(const double degree1, const double degree2) { + return std::fmod(degree1 - degree2, (M_PI * 2)); +} + +double SumDegree(const double degree1, const double degree2) { + return std::fmod(degree1 + degree2, 360.0); +} + +double SubDegree(const double degree1, const double degree2) { + return std::fmod(degree1 - degree2, 360.0); +} + double ToRadians(const double degree) { return degree * M_PI / 180.0; } @@ -157,4 +177,37 @@ double Distance(const vector2i& v1, const vector2i& v2) { return std::sqrt(std::pow(v1.x - v2.x, 2) + std::pow(v1.y - v2.y, 2)); } +double CalculateAngleBetweenTwoVectors(const vector2d& v1, const vector2d& v3) { + return std::acos(v1.Dot(v3) / (v1.Magnitude() * v3.Magnitude())); +} + +double CalculateAngleBetweenTwoVectorsSigned(const vector2d& v1, + const vector2d& v3) { + auto angle = std::acos(v1.Dot(v3) / (v1.Magnitude() * v3.Magnitude())); + // if v1 is on the left side of v2, then angle is negative + const vector2d v2; + double orientation_val = + (v2.y - v1.y) * (v3.x - v2.x) - (v2.x - v1.x) * (v3.y - v2.y); + if (orientation_val > 0.0) { + angle = -angle; + } + return angle; +} + +double CalculateAngleBetweenThreeVectorsSigned(const vector2d& v1, + const vector2d& v2, + const vector2d& v3) { + const auto v1_base = v1 - v2; + const auto v3_base = v3 - v2; + auto angle = std::acos(v1_base.Dot(v3_base) / + (v1_base.Magnitude() * v3_base.Magnitude())); + // if v1 is on the left side of v2, then angle is negative + double orientation_val = + (v2.y - v1.y) * (v3.x - v2.x) - (v2.x - v1.x) * (v3.y - v2.y); + if (orientation_val > 0.0) { + angle = -angle; + } + return angle; +} + } // namespace wolfenstein diff --git a/src/TextureManager/src/texture_manager.cpp b/src/TextureManager/src/texture_manager.cpp index baff6d2..aa40662 100644 --- a/src/TextureManager/src/texture_manager.cpp +++ b/src/TextureManager/src/texture_manager.cpp @@ -1,5 +1,6 @@ #include "TextureManager/texture_manager.h" #include +#include namespace wolfenstein { @@ -24,6 +25,9 @@ void TextureManager::InitManager(SDL_Renderer* renderer) { LoadTexture(5, texture_path + "5.png"); LoadTexture(6, texture_path + "candlebra.png"); LoadTexture(7, texture_path + "solid_black.png"); + + std::string sprite_path = std::string(RESOURCE_DIR) + "sprites/"; + LoadTexture(8, sprite_path + "npc/caco_demon/pain/0.png"); } void TextureManager::LoadTexture(uint16_t texture_id, diff --git a/src/TimeManager/include/TimeManager/time_manager.h b/src/TimeManager/include/TimeManager/time_manager.h index a4de4a3..06dcf05 100644 --- a/src/TimeManager/include/TimeManager/time_manager.h +++ b/src/TimeManager/include/TimeManager/time_manager.h @@ -23,7 +23,7 @@ class TimeManager void InitClock(); void CalculateDeltaTime(); - void SleepForHz(int hz); + void SleepForHz(double hz); double GetDeltaTime(); double GetFramePerSecond(); diff --git a/src/TimeManager/src/time_manager.cpp b/src/TimeManager/src/time_manager.cpp index 0d8e931..9a1bc2e 100644 --- a/src/TimeManager/src/time_manager.cpp +++ b/src/TimeManager/src/time_manager.cpp @@ -13,7 +13,7 @@ void TimeManager::CalculateDeltaTime() { previos_time_point = current_time_point; } -void TimeManager::SleepForHz(int hz) { +void TimeManager::SleepForHz(double hz) { if (hz == 0) { return; }