From faa6e109f6956fe4aaf9365a0b8814f0a478b9ef Mon Sep 17 00:00:00 2001 From: Kapitan Date: Wed, 22 Dec 2021 16:42:26 +0100 Subject: [PATCH] Zad 3 final --- 2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj | 6 ++ 2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters | 3 + 2dgk_zad3/2dgk_zad3/Constants.h | 37 ++++---- 2dgk_zad3/2dgk_zad3/KCircle.cpp | 13 +-- 2dgk_zad3/2dgk_zad3/KCircle.h | 10 +- 2dgk_zad3/2dgk_zad3/KCollider.h | 8 +- 2dgk_zad3/2dgk_zad3/KExit.h | 4 +- 2dgk_zad3/2dgk_zad3/KFont.cpp | 47 ++++++++-- 2dgk_zad3/2dgk_zad3/KGame.cpp | 94 +++++++------------ 2dgk_zad3/2dgk_zad3/KGame.h | 7 +- 2dgk_zad3/2dgk_zad3/KInput.cpp | 1 + 2dgk_zad3/2dgk_zad3/KObject.cpp | 4 +- 2dgk_zad3/2dgk_zad3/KObject.h | 5 +- 2dgk_zad3/2dgk_zad3/KPawn.cpp | 12 ++- 2dgk_zad3/2dgk_zad3/KPawn.h | 3 +- 2dgk_zad3/2dgk_zad3/KPlayerController.cpp | 1 - 2dgk_zad3/2dgk_zad3/KPlayerController.h | 8 +- 2dgk_zad3/2dgk_zad3/KRect.h | 15 +-- 2dgk_zad3/2dgk_zad3/KSettings.cpp | 93 +++++++++++++++++- 2dgk_zad3/2dgk_zad3/KSettings.h | 33 ++++++- 2dgk_zad3/2dgk_zad3/KTexture.cpp | 4 +- 2dgk_zad3/2dgk_zad3/Property.h | 54 +++++++++++ 22 files changed, 322 insertions(+), 140 deletions(-) create mode 100644 2dgk_zad3/2dgk_zad3/Property.h diff --git a/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj index c0a36d3..c4612ad 100644 --- a/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj +++ b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj @@ -203,6 +203,7 @@ + @@ -249,4 +250,9 @@ + + + + + \ No newline at end of file diff --git a/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters index 74e4d9b..e8a8395 100644 --- a/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters +++ b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters @@ -147,6 +147,9 @@ Header Files + + Header Files + diff --git a/2dgk_zad3/2dgk_zad3/Constants.h b/2dgk_zad3/2dgk_zad3/Constants.h index 816a48e..5792a3f 100644 --- a/2dgk_zad3/2dgk_zad3/Constants.h +++ b/2dgk_zad3/2dgk_zad3/Constants.h @@ -1,22 +1,21 @@ #pragma once -namespace KapitanGame { - namespace Constants { - constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 3 (Lab 11-12)"; - //Analog joystick dead zone - constexpr int JOYSTICK_DEAD_ZONE = 8000; - //Screen dimension constants - constexpr int WINDOW_DEAD_ZONE = 100; - constexpr int SCREEN_WIDTH = 640; - constexpr int SCREEN_HEIGHT = 480; - constexpr float SCREEN_RATIO = static_cast(SCREEN_WIDTH) / SCREEN_HEIGHT; - constexpr int TILE_WIDTH = 32; - constexpr int TILE_HEIGHT = 32; - constexpr float SPEED = 200.f; - constexpr float SMOOTH = 0.4f; - constexpr float JUMP_SPEED = 300.f; - constexpr float GRAVITY = 450.f; - constexpr float MAX_JUMP_VELOCITY = 1000.f; - constexpr float MAX_GRAVITY = 1000.f; - } +namespace KapitanGame::Constants +{ + constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 3 (Lab 11-12)"; + //Analog joystick dead zone + constexpr int JOYSTICK_DEAD_ZONE = 8000; + //Screen dimension constants + constexpr int WINDOW_DEAD_ZONE = 100; + constexpr int SCREEN_WIDTH = 640; + constexpr int SCREEN_HEIGHT = 480; + constexpr float SCREEN_RATIO = static_cast(SCREEN_WIDTH) / SCREEN_HEIGHT; + constexpr int TILE_WIDTH = 32; + constexpr int TILE_HEIGHT = 32; + constexpr float SPEED = 200.f; + constexpr float SMOOTH = 0.4f; + constexpr float JUMP_SPEED = 300.f; + constexpr float HORIZONTAL_DISTANCE_TO_MAX_JUMP_HEIGHT = TILE_WIDTH * 4.f; + constexpr float MAX_JUMP_HEIGHT = TILE_HEIGHT * 4.f; + constexpr float MAX_GRAVITY = 1000.f; } diff --git a/2dgk_zad3/2dgk_zad3/KCircle.cpp b/2dgk_zad3/2dgk_zad3/KCircle.cpp index 51d562c..2533f88 100644 --- a/2dgk_zad3/2dgk_zad3/KCircle.cpp +++ b/2dgk_zad3/2dgk_zad3/KCircle.cpp @@ -1,5 +1,6 @@ #include "KCircle.h" +#include #include #include "KRect.h" @@ -13,13 +14,11 @@ namespace KapitanGame { bool KCircle::IsCollision(const KCollider* other) const { - const auto circle = dynamic_cast(other); - if (circle != nullptr) + if (const auto circle = dynamic_cast(other); circle != nullptr) return IsCollision(circle); - const auto rect = dynamic_cast(other); - if (rect != nullptr) + if (const auto rect = dynamic_cast(other); rect != nullptr) return IsCollision(rect); throw std::runtime_error("unsupported shape"); @@ -27,12 +26,10 @@ namespace KapitanGame { KVector2D KCircle::GetSeparationVector(const KCollider* other) const { - const auto circle = dynamic_cast(other); - if (circle != nullptr) + if (const auto circle = dynamic_cast(other); circle != nullptr) return GetSeparationVector(circle); - const auto rect = dynamic_cast(other); - if (rect != nullptr) + if (const auto rect = dynamic_cast(other); rect != nullptr) return GetSeparationVector(rect); throw std::runtime_error("unsupported shape"); diff --git a/2dgk_zad3/2dgk_zad3/KCircle.h b/2dgk_zad3/2dgk_zad3/KCircle.h index a4db204..3081a5a 100644 --- a/2dgk_zad3/2dgk_zad3/KCircle.h +++ b/2dgk_zad3/2dgk_zad3/KCircle.h @@ -11,8 +11,8 @@ namespace KapitanGame { class KCircle final : public KCollider { public: - KCircle(KObject* parent, const float radius); - float GetRadius() const; + KCircle(KObject* parent, float radius); + [[nodiscard]] float GetRadius() const; private: KVector2D GetSeparationVector(const KCircle* other) const; KVector2D GetSeparationVector(const KRect* other) const; @@ -21,9 +21,9 @@ namespace KapitanGame { public: bool IsCollision(const KCollider* other) const override; KVector2D GetSeparationVector(const KCollider* other) const override; - KVector2D GetSeparationVector(const SDL_FRect& map) const override; - float GetWidth() const override; - float GetHeight() const override; + [[nodiscard]] KVector2D GetSeparationVector(const SDL_FRect& map) const override; + [[nodiscard]] float GetWidth() const override; + [[nodiscard]] float GetHeight() const override; private: float Radius{ 1.f }; }; diff --git a/2dgk_zad3/2dgk_zad3/KCollider.h b/2dgk_zad3/2dgk_zad3/KCollider.h index 77e8e07..eb14f63 100644 --- a/2dgk_zad3/2dgk_zad3/KCollider.h +++ b/2dgk_zad3/2dgk_zad3/KCollider.h @@ -23,10 +23,10 @@ namespace KapitanGame { virtual ~KCollider() = default; virtual bool IsCollision(const KCollider* other) const = 0; virtual KVector2D GetSeparationVector(const KCollider* other) const = 0; - virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0; - virtual float GetWidth() const = 0; - virtual float GetHeight() const = 0; - KObject* GetParent() const; + [[nodiscard]] virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0; + [[nodiscard]] virtual float GetWidth() const = 0; + [[nodiscard]] virtual float GetHeight() const = 0; + [[nodiscard]] KObject* GetParent() const; private: KObject* Parent; }; diff --git a/2dgk_zad3/2dgk_zad3/KExit.h b/2dgk_zad3/2dgk_zad3/KExit.h index 60c5d45..2c09a9b 100644 --- a/2dgk_zad3/2dgk_zad3/KExit.h +++ b/2dgk_zad3/2dgk_zad3/KExit.h @@ -10,11 +10,11 @@ namespace KapitanGame public: KExit(const KVector2D& position, const KTexture& texture) : KObject(position, texture), - Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f) + Collider(this, static_cast(texture.GetWidth()), static_cast(texture.GetHeight())) { } - const KCollider* GetCollider() const override; + [[nodiscard]] const KCollider* GetCollider() const override; private: KRect Collider; }; diff --git a/2dgk_zad3/2dgk_zad3/KFont.cpp b/2dgk_zad3/2dgk_zad3/KFont.cpp index 7bbb11d..16dea77 100644 --- a/2dgk_zad3/2dgk_zad3/KFont.cpp +++ b/2dgk_zad3/2dgk_zad3/KFont.cpp @@ -1,5 +1,7 @@ #include "KFont.h" +#include + #include "KTexture.h" namespace KapitanGame @@ -48,16 +50,49 @@ namespace KapitanGame KTexture KFont::GetTextTexture(const std::string& text, const SDL_Color textColor, SDL_Renderer* renderer) const { KTexture texture; - SDL_Surface* textSurface = TTF_RenderText_Solid(Font, text.c_str(), textColor); - if (textSurface == nullptr) + constexpr int spacing = 1; + int width, height = width = 0; + std::istringstream inputText; + inputText.str(text); + for(std::string line; std::getline(inputText, line);) { - printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError()); + int w, h; + TTF_SizeText(Font, line.c_str(), &w, &h); + if (w > width) width = w; + height += w+spacing; } - else + if (height > 0) + height -= spacing; + inputText.clear(); + inputText.seekg(0); + SDL_Surface* textureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 8, SDL_PIXELFORMAT_INDEX8); { - texture.LoadFromSurface(textSurface, renderer); - SDL_FreeSurface(textSurface); + const SDL_Palette* palette = textureSurface->format->palette; + palette->colors[0].r = 255 - textColor.r; + palette->colors[0].g = 255 - textColor.g; + palette->colors[0].b = 255 - textColor.b; + palette->colors[1].r = textColor.r; + palette->colors[1].g = textColor.g; + palette->colors[1].b = textColor.b; + palette->colors[1].a = textColor.a; } + SDL_SetColorKey(textureSurface, SDL_TRUE, 0); + int y = 0; + for (std::string line; std::getline(inputText, line);) { + if (SDL_Surface* textSurface = TTF_RenderText_Solid(Font, line.c_str(), textColor); textSurface == nullptr) + { + printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError()); + } + else + { + SDL_Rect destRect{0, y, textSurface->w, textSurface->h}; + SDL_BlitSurface(textSurface, nullptr, textureSurface, &destRect); + y += textSurface->h + spacing; + SDL_FreeSurface(textSurface); + } + } + texture.LoadFromSurface(textureSurface, renderer); + SDL_FreeSurface(textureSurface); return texture; } diff --git a/2dgk_zad3/2dgk_zad3/KGame.cpp b/2dgk_zad3/2dgk_zad3/KGame.cpp index 830be5a..418d9e5 100644 --- a/2dgk_zad3/2dgk_zad3/KGame.cpp +++ b/2dgk_zad3/2dgk_zad3/KGame.cpp @@ -11,18 +11,13 @@ #include "KCamera.h" #include "KCirclePawn.h" #include "KExit.h" -#include "KRectPawn.h" #include "KTexture.h" #include "KTile.h" #include "KVector2d.h" #include "KWall.h" -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - namespace KapitanGame { - KGame::KGame() : Time(0), PreviousTime(0), Map() + KGame::KGame() : Time(0), PreviousTime(0), Map(), Settings(Constants::MAX_JUMP_HEIGHT, Constants::HORIZONTAL_DISTANCE_TO_MAX_JUMP_HEIGHT) { //Initialize SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) @@ -109,7 +104,10 @@ namespace KapitanGame { if (mapWidth < static_cast(line.length() * Constants::TILE_WIDTH)) mapWidth = static_cast(line.length()) * Constants::TILE_WIDTH; for (auto i = 0ull; i < line.length(); ++i) { - KVector2D position{ static_cast(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2) , static_cast(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) }; + KVector2D position{ + static_cast(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2), // NOLINT(bugprone-integer-division) + static_cast(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) // NOLINT(bugprone-integer-division) + }; switch (line[i]) { case '#': @@ -150,7 +148,7 @@ namespace KapitanGame { break; } - PlayerControllers.emplace_back(std::make_shared(player, this)); + PlayerControllers.emplace_back(std::make_shared(player)); PlayerControllers.back()->SetupInputBindings(Input); } Textures.emplace("wall.bmp", KTexture()); @@ -168,11 +166,8 @@ namespace KapitanGame { Fonts.erase("PressStart2P-Regular"); success = false; } - //Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextWithOutlineTexture("0:0", { 0xFF,0xFF,0xFF,0xFF }, { 0,0,0,0xFF }, 1, Renderer)); - //Textures.emplace("Text_Winner", KTexture()); - std::ifstream configFile("config.json"); - if (configFile.fail()) { + if (std::ifstream configFile("config.json"); configFile.fail()) { printf("Failed to load config.json!\n"); success = false; } @@ -218,8 +213,7 @@ namespace KapitanGame { camera.Update(Pawns, Map); - VelocityTextureDirty = true; - GravityTextureDirty = true; + SettingsTextTextureDirty = true; Time = PreviousTime = SDL_GetTicks(); printf("\n"); @@ -229,7 +223,7 @@ namespace KapitanGame { { PreviousTime = Time; Time = SDL_GetTicks(); - float deltaTime = (Time - PreviousTime) * 0.001f; + float deltaTime = static_cast(Time - PreviousTime) * 0.001f; Input.HandleInputPreEvents(); @@ -255,31 +249,28 @@ namespace KapitanGame { if (devMode >= 1) { if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2)) { - CollisionEnabled = !CollisionEnabled; + Settings.CollisionEnabled = !Settings.CollisionEnabled; } if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F3)) { - Settings.JumpVelocity -= 0.1f; - if (Settings.JumpVelocity < 0) Settings.JumpVelocity = 0; - VelocityTextureDirty = true; + Settings.MaxJumpHeight -= 0.1f; + //Settings.SetMaxJumpHeight(Settings.GetMaxJumpHeight() - 0.1f); + SettingsTextTextureDirty = true; } if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F4)) { - Settings.JumpVelocity += 0.1f; - if (Settings.JumpVelocity > Constants::MAX_JUMP_VELOCITY) Settings.JumpVelocity = Constants::MAX_JUMP_VELOCITY; - VelocityTextureDirty = true; + Settings.MaxJumpHeight += 0.1f; + SettingsTextTextureDirty = true; } if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F5)) { - Settings.Gravity -= 0.1f; - if (Settings.Gravity < 0) Settings.Gravity = 0; - GravityTextureDirty = true; + Settings.HorizontalDistanceToMaxJumpHeight -= 0.1f; + SettingsTextTextureDirty = true; } if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F6)) { - Settings.Gravity += 0.1f; - if (Settings.Gravity > Constants::MAX_GRAVITY) Settings.Gravity = Constants::MAX_GRAVITY; - GravityTextureDirty = true; + Settings.HorizontalDistanceToMaxJumpHeight += 0.1f; + SettingsTextTextureDirty = true; } } @@ -291,7 +282,7 @@ namespace KapitanGame { if (!Playing) break; pawn->MovementStep(deltaTime); } - if (CollisionEnabled) { + if (Settings.CollisionEnabled) { for (const auto& pawn : Pawns) { if (!Playing) break; pawn->CollisionDetectionStep(Objects); @@ -309,14 +300,19 @@ namespace KapitanGame { camera.Update(Pawns, Map); } - if (VelocityTextureDirty) { - Textures.insert_or_assign("Text_Velocity", Fonts["PressStart2P-Regular"].GetTextTexture(Utils::StringFormat("Velocity: %f", Settings.JumpVelocity), { 0,0,0,0xFF }, Renderer)); - VelocityTextureDirty = false; - } - if (GravityTextureDirty) { - Textures.insert_or_assign("Text_Gravity", Fonts["PressStart2P-Regular"].GetTextTexture(Utils::StringFormat("Gravity: %f", Settings.Gravity), { 0,0,0,0xFF }, Renderer)); - GravityTextureDirty = false; - } + //if (SettingsTextTextureDirty) { + Textures.insert_or_assign("Text_Settings", Fonts["PressStart2P-Regular"].GetTextTexture( + Utils::StringFormat( + "Max Jump Height: %f\nHorizontal Distance to Max Jump Height: %f\nInitial Jump Velocity: %f\nGravity: %f\nPlayer Position X: %f\nPlayer Position Y: %f", + static_cast(Settings.MaxJumpHeight), + static_cast(Settings.HorizontalDistanceToMaxJumpHeight), + static_cast(Settings.JumpInitialVelocity), + static_cast(Settings.Gravity), + Pawns.back()->GetPosition().X, + Pawns.back()->GetPosition().Y), {0, 0, 0, 0xFF}, + Renderer)); + //SettingsTextTextureDirty = false; + //} if (!Playing) @@ -326,16 +322,6 @@ namespace KapitanGame { LoadLevel(); debugCamera.SetDebug(Map); camera.Update(Pawns, Map); - if (ShowWinner) - { - for (auto i : Utils::KPlayerIterator()) - { - Scores[static_cast(i)] = 0; - } - //Textures.erase("Text_Score"); - //Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextWithOutlineTexture(Utils::StringFormat("%d:%d", Scores[0], Scores[1]), { 0xFF,0xFF,0xFF,0xFF }, { 0,0,0,0xFF }, 1, Renderer)); - ShowWinner = false; - } Playing = true; continue; } @@ -355,22 +341,10 @@ namespace KapitanGame { for (const auto& pawn : Pawns) { pawn->Render(Renderer, cameraInUse); } - if (const auto exit = Exit.lock()) { - const float exitX = camera.GetViewport().x + Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f - exit->GetPosition().X + exit->GetCollider()->GetWidth() / 2.f; - const float exitY = camera.GetViewport().y + 25.f - exit->GetPosition().Y + exit->GetCollider()->GetHeight() / 2.f; - const double degrees = atan2(-exitX, exitY) * (180.f / M_PI); - Textures["arrow.bmp"].RenderEx(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f, 25.f, degrees); - } - } - if (ShowWinner) - { - Textures["Text_Winner"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Winner"].GetWidth() / 2.f, 25.f); } - //Textures["Text_Score"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Score"].GetWidth() / 2.f, Constants::SCREEN_HEIGHT - 10.f - Textures["Text_Score"].GetHeight()); if (devMode >= 1) { - Textures["Text_Velocity"].Render(Renderer, 10.f, 25.f); - Textures["Text_Gravity"].Render(Renderer, 10.f, 30.f + Textures["Text_Velocity"].GetHeight()); + Textures["Text_Settings"].Render(Renderer, 10.f, 25.f); } if (devMode >= 2) { diff --git a/2dgk_zad3/2dgk_zad3/KGame.h b/2dgk_zad3/2dgk_zad3/KGame.h index d54b48f..6a4d391 100644 --- a/2dgk_zad3/2dgk_zad3/KGame.h +++ b/2dgk_zad3/2dgk_zad3/KGame.h @@ -20,7 +20,6 @@ namespace KapitanGame { public: KGame(); ~KGame(); - void Win(KPlayer player); KGame(const KGame& other) = delete; KGame(KGame&& other) noexcept = delete; KGame& operator=(const KGame& other) = delete; @@ -40,12 +39,9 @@ namespace KapitanGame { uint32_t Time; uint32_t PreviousTime; SDL_FRect Map; - bool CollisionEnabled = true; - bool ShowWinner = false; std::weak_ptr Exit; KSettings Settings; - bool VelocityTextureDirty; - bool GravityTextureDirty; + bool SettingsTextTextureDirty = true; bool LoadLevel(); bool LoadMedia(); @@ -53,7 +49,6 @@ namespace KapitanGame { int LvlCounter = 1; bool Playing = true; uint32_t RestartTick = -1; - short Scores[static_cast(KPlayer::Player2) + 1] = { 0,0 }; }; } diff --git a/2dgk_zad3/2dgk_zad3/KInput.cpp b/2dgk_zad3/2dgk_zad3/KInput.cpp index 0b5544b..a13b3c6 100644 --- a/2dgk_zad3/2dgk_zad3/KInput.cpp +++ b/2dgk_zad3/2dgk_zad3/KInput.cpp @@ -121,6 +121,7 @@ namespace KapitanGame { } } break; + default: break; } } diff --git a/2dgk_zad3/2dgk_zad3/KObject.cpp b/2dgk_zad3/2dgk_zad3/KObject.cpp index d9cbed9..f11f666 100644 --- a/2dgk_zad3/2dgk_zad3/KObject.cpp +++ b/2dgk_zad3/2dgk_zad3/KObject.cpp @@ -1,5 +1,7 @@ #include "KObject.h" +#include + #include "KCamera.h" namespace KapitanGame @@ -13,7 +15,7 @@ namespace KapitanGame void KObject::Render(SDL_Renderer* renderer, const KCamera& camera) const { - Texture.Render(renderer, Position.X - Texture.GetWidth() / 2.f - camera.GetViewport().x, Position.Y - Texture.GetHeight() / 2.f - camera.GetViewport().y, nullptr, camera.GetScale()); + Texture.Render(renderer, Position.X - Texture.GetWidth() / 2.f - camera.GetViewport().x, Position.Y - Texture.GetHeight() / 2.f - camera.GetViewport().y, nullptr, camera.GetScale()); // NOLINT(clang-diagnostic-implicit-int-float-conversion, bugprone-narrowing-conversions, cppcoreguidelines-narrowing-conversions) } KVector2D KObject::GetPosition() const diff --git a/2dgk_zad3/2dgk_zad3/KObject.h b/2dgk_zad3/2dgk_zad3/KObject.h index 14482fa..b663278 100644 --- a/2dgk_zad3/2dgk_zad3/KObject.h +++ b/2dgk_zad3/2dgk_zad3/KObject.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include "KTexture.h" #include "KVector2d.h" @@ -15,8 +16,8 @@ namespace KapitanGame KObject(const KVector2D& position, const KTexture& texture); virtual ~KObject() = default; void Render(SDL_Renderer* renderer, const KCamera& camera) const; - KVector2D GetPosition() const; - virtual const KCollider* GetCollider() const = 0; + [[nodiscard]] KVector2D GetPosition() const; + [[nodiscard]] virtual const KCollider* GetCollider() const = 0; const int Id; static std::atomic IdCounter; protected: diff --git a/2dgk_zad3/2dgk_zad3/KPawn.cpp b/2dgk_zad3/2dgk_zad3/KPawn.cpp index c8cc29a..72c2f3b 100644 --- a/2dgk_zad3/2dgk_zad3/KPawn.cpp +++ b/2dgk_zad3/2dgk_zad3/KPawn.cpp @@ -68,6 +68,10 @@ namespace KapitanGame CanDoubleJump = true; HasJumped = false; } + if (separationVector.Y > 0) + { + Velocity.Y = 0; + } } void KPawn::AddXMovementInput(const float& input) @@ -77,8 +81,8 @@ namespace KapitanGame void KPawn::StopJump() { if (!CanJump) { - if (Velocity.Y < -Settings->ShortJumpVelocity()) - Velocity.Y = -Settings->ShortJumpVelocity(); + if (Velocity.Y < -Settings->ShortJumpVelocity) + Velocity.Y = -Settings->ShortJumpVelocity; } } @@ -90,12 +94,12 @@ namespace KapitanGame if (CanJump) { CanJump = false; HasJumped = true; - Velocity.Y = -Settings->JumpVelocity; + Velocity.Y = -Settings->JumpInitialVelocity; } else if (HasJumped && CanDoubleJump) { CanDoubleJump = false; - Velocity.Y = -Settings->JumpVelocity; + Velocity.Y = -Settings->JumpInitialVelocity; } } } diff --git a/2dgk_zad3/2dgk_zad3/KPawn.h b/2dgk_zad3/2dgk_zad3/KPawn.h index f255102..dbb3eca 100644 --- a/2dgk_zad3/2dgk_zad3/KPawn.h +++ b/2dgk_zad3/2dgk_zad3/KPawn.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include "KObject.h" @@ -7,7 +8,7 @@ namespace KapitanGame { - struct KSettings; + class KSettings; class KPlayerController; class KPawn : public KObject diff --git a/2dgk_zad3/2dgk_zad3/KPlayerController.cpp b/2dgk_zad3/2dgk_zad3/KPlayerController.cpp index e7010d7..06665ba 100644 --- a/2dgk_zad3/2dgk_zad3/KPlayerController.cpp +++ b/2dgk_zad3/2dgk_zad3/KPlayerController.cpp @@ -1,6 +1,5 @@ #include "KPlayerController.h" -#include "KGame.h" #include "KInput.h" namespace KapitanGame { diff --git a/2dgk_zad3/2dgk_zad3/KPlayerController.h b/2dgk_zad3/2dgk_zad3/KPlayerController.h index 3b1913c..9b3b7ad 100644 --- a/2dgk_zad3/2dgk_zad3/KPlayerController.h +++ b/2dgk_zad3/2dgk_zad3/KPlayerController.h @@ -4,15 +4,13 @@ #include "KVector2d.h" namespace KapitanGame { - class KGame; class KInput; class KPlayerController : public std::enable_shared_from_this { public: - KPlayerController(const KPlayer player, KGame* const game) - : Player(player), - Game(game) + explicit KPlayerController(const KPlayer player) + : Player(player) { } @@ -21,7 +19,6 @@ namespace KapitanGame { void StartJump(); void StopJump(); void Update(float deltaTime); - void NotifyWin() const; void Possess(KPawn* pawn); void UnPossess(); const KPlayer& GetPlayer() const; @@ -29,7 +26,6 @@ namespace KapitanGame { KVector2D Input{ 0.f, 0.f }; const KPlayer Player; KPawn* Pawn{}; - KGame* Game; bool InputStartJump{}; bool InputStopJump{}; }; diff --git a/2dgk_zad3/2dgk_zad3/KRect.h b/2dgk_zad3/2dgk_zad3/KRect.h index 66cd3ca..825aa05 100644 --- a/2dgk_zad3/2dgk_zad3/KRect.h +++ b/2dgk_zad3/2dgk_zad3/KRect.h @@ -15,20 +15,21 @@ namespace KapitanGame { Height(height) { } - float GetWidth() const override; - float GetHeight() const override; + + [[nodiscard]] float GetWidth() const override; + [[nodiscard]] float GetHeight() const override; static KVector2D GetSeparationVector(float left, float right, float top, float bottom); bool IsCollision(const KCollider* other) const override; KVector2D GetSeparationVector(const KCollider* other) const override; - KVector2D GetSeparationVector(const SDL_FRect& map) const override; + [[nodiscard]] KVector2D GetSeparationVector(const SDL_FRect& map) const override; private: KVector2D GetSeparationVector(const KCircle* other) const; KVector2D GetSeparationVector(const KRect* other) const; bool IsCollision(const KCircle* other) const; - float GetLeft() const; - float GetRight() const; - float GetBottom() const; - float GetTop() const; + [[nodiscard]] float GetLeft() const; + [[nodiscard]] float GetRight() const; + [[nodiscard]] float GetBottom() const; + [[nodiscard]] float GetTop() const; bool IsCollision(const KRect* other) const; float Width; float Height; diff --git a/2dgk_zad3/2dgk_zad3/KSettings.cpp b/2dgk_zad3/2dgk_zad3/KSettings.cpp index 1597b37..89deca4 100644 --- a/2dgk_zad3/2dgk_zad3/KSettings.cpp +++ b/2dgk_zad3/2dgk_zad3/KSettings.cpp @@ -1,9 +1,98 @@ #include "KSettings.h" +#include +#include +#include "Constants.h" + namespace KapitanGame { - float KSettings::ShortJumpVelocity() const + KSettings::KSettings(const float maxJumpHeight, const float horizontalDistanceToMaxJumpHeight) : MaxJumpHeightValue(maxJumpHeight), + HorizontalDistanceToMaxJumpHeightValue(horizontalDistanceToMaxJumpHeight), + TimeToMaxHeightValue(NAN), + GravityValue(NAN), + JumpInitialVelocityValue(NAN), + ShortJumpVelocityValue(NAN), + CollisionEnabledValue(true), + Dirty(true), + MaxJumpHeight(this, &KSettings::GetMaxJumpHeight, &KSettings::SetMaxJumpHeight), + HorizontalDistanceToMaxJumpHeight(this, &KSettings::GetHorizontalDistanceToMaxJumpHeight, &KSettings::SetHorizontalDistanceToMaxJumpHeight), + TimeToMaxHeight(this, &KSettings::GetTimeToMaxHeight), + Gravity(this, &KSettings::GetGravity), + JumpInitialVelocity(this, &KSettings::GetJumpInitialVelocity), + ShortJumpVelocity(this, &KSettings::GetShortJumpVelocity), + CollisionEnabled(this, &KSettings::GetCollisionEnabled, &KSettings::SetCollisionEnabled) { - return JumpVelocity / 2.f; + } + + void KSettings::SetCollisionEnabled(const bool value) + { + if (value != CollisionEnabledValue) + CollisionEnabledValue = value; + } + + void KSettings::SetMaxJumpHeight(const float h) + { + if (h <= 0.f && MaxJumpHeightValue <= 0.f) return; + if (MaxJumpHeightValue != h) { // NOLINT(clang-diagnostic-float-equal) + MaxJumpHeightValue = std::max(h, 0.f); + Dirty = true; + } + } + + void KSettings::SetHorizontalDistanceToMaxJumpHeight(const float xn) + { + if (xn <= 0.f && HorizontalDistanceToMaxJumpHeightValue <= 0.f) return; + if (HorizontalDistanceToMaxJumpHeightValue != xn) { // NOLINT(clang-diagnostic-float-equal) + HorizontalDistanceToMaxJumpHeightValue = std::max(xn, 0.f); + Dirty = true; + } + } + + // ReSharper disable once CppMemberFunctionMayBeConst + bool KSettings::GetCollisionEnabled() + { + return CollisionEnabledValue; + } + + float KSettings::GetTimeToMaxHeight() + { + if (Dirty) + TimeToMaxHeightValue = HorizontalDistanceToMaxJumpHeightValue / Constants::SPEED; + return TimeToMaxHeightValue; + } + + float KSettings::GetGravity() + { + if (Dirty) { + const auto timeToMaxHeight = GetTimeToMaxHeight(); + GravityValue = 2.0f * MaxJumpHeightValue / (timeToMaxHeight * timeToMaxHeight); + } + return GravityValue; + } + + float KSettings::GetJumpInitialVelocity() + { + if (Dirty) + JumpInitialVelocityValue = 2.0f * MaxJumpHeightValue / GetTimeToMaxHeight(); + return JumpInitialVelocityValue; + } + + float KSettings::GetShortJumpVelocity() + { + if (Dirty) + ShortJumpVelocityValue = GetJumpInitialVelocity() / 2.f; + return ShortJumpVelocityValue; + } + + // ReSharper disable once CppMemberFunctionMayBeConst + float KSettings::GetMaxJumpHeight() + { + return MaxJumpHeightValue; + } + + // ReSharper disable once CppMemberFunctionMayBeConst + float KSettings::GetHorizontalDistanceToMaxJumpHeight() + { + return HorizontalDistanceToMaxJumpHeightValue; } } diff --git a/2dgk_zad3/2dgk_zad3/KSettings.h b/2dgk_zad3/2dgk_zad3/KSettings.h index 31b189d..2c160ac 100644 --- a/2dgk_zad3/2dgk_zad3/KSettings.h +++ b/2dgk_zad3/2dgk_zad3/KSettings.h @@ -1,14 +1,37 @@ #pragma once -#include "Constants.h" +#include "Property.h" namespace KapitanGame { - struct KSettings + class KSettings final { - float Gravity = Constants::GRAVITY; - float JumpVelocity = Constants::JUMP_SPEED; + float MaxJumpHeightValue; + float HorizontalDistanceToMaxJumpHeightValue; + float TimeToMaxHeightValue; + float GravityValue; + float JumpInitialVelocityValue; + float ShortJumpVelocityValue; + bool CollisionEnabledValue; + bool Dirty; - [[nodiscard]] float ShortJumpVelocity() const; + public: + + KSettings(float maxJumpHeight, float horizontalDistanceToMaxJumpHeight); + const Property MaxJumpHeight, HorizontalDistanceToMaxJumpHeight; + const ReadOnlyProperty TimeToMaxHeight, Gravity, JumpInitialVelocity, ShortJumpVelocity; + const Property CollisionEnabled; + + private: + void SetCollisionEnabled(bool value); + void SetMaxJumpHeight(float h); + void SetHorizontalDistanceToMaxJumpHeight(float xn); + bool GetCollisionEnabled(); + float GetTimeToMaxHeight(); + float GetGravity(); + float GetJumpInitialVelocity(); + float GetShortJumpVelocity(); + float GetMaxJumpHeight(); + float GetHorizontalDistanceToMaxJumpHeight(); }; } diff --git a/2dgk_zad3/2dgk_zad3/KTexture.cpp b/2dgk_zad3/2dgk_zad3/KTexture.cpp index ac7798c..244cccf 100644 --- a/2dgk_zad3/2dgk_zad3/KTexture.cpp +++ b/2dgk_zad3/2dgk_zad3/KTexture.cpp @@ -1,5 +1,7 @@ #include "KTexture.h" +#include + namespace KapitanGame { KTexture::KTexture() : Texture(nullptr), Width(0), Height(0) { @@ -142,4 +144,4 @@ namespace KapitanGame { { return Height; } -} \ No newline at end of file +} diff --git a/2dgk_zad3/2dgk_zad3/Property.h b/2dgk_zad3/2dgk_zad3/Property.h new file mode 100644 index 0000000..f4c6a5e --- /dev/null +++ b/2dgk_zad3/2dgk_zad3/Property.h @@ -0,0 +1,54 @@ +#pragma once +namespace KapitanGame +{ + template + class ReadOnlyProperty { + protected: + C* Owner; + T(C::* Getter)(); + public: + ReadOnlyProperty() : Owner(), Getter() {} + ReadOnlyProperty(C* owner, T(C::* getter)()) : Owner(owner), Getter(getter) {} + + [[nodiscard]] T Get() const { + return (Owner->*Getter)(); + } + + // ReSharper disable once CppNonExplicitConversionOperator + operator T() const { + return Get(); + } + }; + + template + class Property : public ReadOnlyProperty { + void(C::* Setter)(T); + public: + Property() : ReadOnlyProperty(), Setter() {} + Property(C* owner, T(C::* getter)(), void(C::* setter)(T)) : ReadOnlyProperty(owner,getter), Setter(setter) {} + void Set(T value) const { + (this->Owner->*Setter)(value); + } + + const Property& operator = (T value) const { // NOLINT(misc-unconventional-assign-operator) + Set(value); + return *this; + } + const Property& operator -= (T value) const { // NOLINT(misc-unconventional-assign-operator) + Set(this->Get() - value); + return *this; + } + const Property& operator += (T value) const { // NOLINT(misc-unconventional-assign-operator) + Set(this->Get() + value); + return *this; + } + const Property& operator *= (T value) const { // NOLINT(misc-unconventional-assign-operator) + Set(this->Get() * value); + return *this; + } + const Property& operator /= (T value) const { // NOLINT(misc-unconventional-assign-operator) + Set(this->Get() / value); + return *this; + } + }; +}