Zad 3 final

This commit is contained in:
Michał Leśniak 2021-12-22 16:42:26 +01:00
parent 9674806687
commit faa6e109f6
22 changed files with 322 additions and 140 deletions

View File

@ -203,6 +203,7 @@
<ClInclude Include="KSettings.h" /> <ClInclude Include="KSettings.h" />
<ClInclude Include="KTexture.h" /> <ClInclude Include="KTexture.h" />
<ClInclude Include="KWall.h" /> <ClInclude Include="KWall.h" />
<ClInclude Include="Property.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="Utils.h" /> <ClInclude Include="Utils.h" />
<ClInclude Include="KVector2d.h" /> <ClInclude Include="KVector2d.h" />
@ -249,4 +250,9 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties />
</VisualStudio>
</ProjectExtensions>
</Project> </Project>

View File

@ -147,6 +147,9 @@
<ClInclude Include="KSettings.h"> <ClInclude Include="KSettings.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Property.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="2dgk_zad3.rc"> <ResourceCompile Include="2dgk_zad3.rc">

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
namespace KapitanGame { namespace KapitanGame::Constants
namespace Constants { {
constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 3 (Lab 11-12)"; constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 3 (Lab 11-12)";
//Analog joystick dead zone //Analog joystick dead zone
constexpr int JOYSTICK_DEAD_ZONE = 8000; constexpr int JOYSTICK_DEAD_ZONE = 8000;
@ -15,8 +15,7 @@ namespace KapitanGame {
constexpr float SPEED = 200.f; constexpr float SPEED = 200.f;
constexpr float SMOOTH = 0.4f; constexpr float SMOOTH = 0.4f;
constexpr float JUMP_SPEED = 300.f; constexpr float JUMP_SPEED = 300.f;
constexpr float GRAVITY = 450.f; constexpr float HORIZONTAL_DISTANCE_TO_MAX_JUMP_HEIGHT = TILE_WIDTH * 4.f;
constexpr float MAX_JUMP_VELOCITY = 1000.f; constexpr float MAX_JUMP_HEIGHT = TILE_HEIGHT * 4.f;
constexpr float MAX_GRAVITY = 1000.f; constexpr float MAX_GRAVITY = 1000.f;
} }
}

View File

@ -1,5 +1,6 @@
#include "KCircle.h" #include "KCircle.h"
#include <SDL_rect.h>
#include <stdexcept> #include <stdexcept>
#include "KRect.h" #include "KRect.h"
@ -13,13 +14,11 @@ namespace KapitanGame {
bool KCircle::IsCollision(const KCollider* other) const bool KCircle::IsCollision(const KCollider* other) const
{ {
const auto circle = dynamic_cast<const KCircle*>(other); if (const auto circle = dynamic_cast<const KCircle*>(other); circle != nullptr)
if (circle != nullptr)
return IsCollision(circle); return IsCollision(circle);
const auto rect = dynamic_cast<const KRect*>(other); if (const auto rect = dynamic_cast<const KRect*>(other); rect != nullptr)
if (rect != nullptr)
return IsCollision(rect); return IsCollision(rect);
throw std::runtime_error("unsupported shape"); throw std::runtime_error("unsupported shape");
@ -27,12 +26,10 @@ namespace KapitanGame {
KVector2D KCircle::GetSeparationVector(const KCollider* other) const KVector2D KCircle::GetSeparationVector(const KCollider* other) const
{ {
const auto circle = dynamic_cast<const KCircle*>(other); if (const auto circle = dynamic_cast<const KCircle*>(other); circle != nullptr)
if (circle != nullptr)
return GetSeparationVector(circle); return GetSeparationVector(circle);
const auto rect = dynamic_cast<const KRect*>(other); if (const auto rect = dynamic_cast<const KRect*>(other); rect != nullptr)
if (rect != nullptr)
return GetSeparationVector(rect); return GetSeparationVector(rect);
throw std::runtime_error("unsupported shape"); throw std::runtime_error("unsupported shape");

View File

@ -11,8 +11,8 @@ namespace KapitanGame {
class KCircle final : public KCollider class KCircle final : public KCollider
{ {
public: public:
KCircle(KObject* parent, const float radius); KCircle(KObject* parent, float radius);
float GetRadius() const; [[nodiscard]] float GetRadius() const;
private: private:
KVector2D GetSeparationVector(const KCircle* other) const; KVector2D GetSeparationVector(const KCircle* other) const;
KVector2D GetSeparationVector(const KRect* other) const; KVector2D GetSeparationVector(const KRect* other) const;
@ -21,9 +21,9 @@ namespace KapitanGame {
public: public:
bool IsCollision(const KCollider* other) const override; bool IsCollision(const KCollider* other) const override;
KVector2D GetSeparationVector(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;
float GetWidth() const override; [[nodiscard]] float GetWidth() const override;
float GetHeight() const override; [[nodiscard]] float GetHeight() const override;
private: private:
float Radius{ 1.f }; float Radius{ 1.f };
}; };

View File

@ -23,10 +23,10 @@ namespace KapitanGame {
virtual ~KCollider() = default; virtual ~KCollider() = default;
virtual bool IsCollision(const KCollider* other) const = 0; virtual bool IsCollision(const KCollider* other) const = 0;
virtual KVector2D GetSeparationVector(const KCollider* other) const = 0; virtual KVector2D GetSeparationVector(const KCollider* other) const = 0;
virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0; [[nodiscard]] virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0;
virtual float GetWidth() const = 0; [[nodiscard]] virtual float GetWidth() const = 0;
virtual float GetHeight() const = 0; [[nodiscard]] virtual float GetHeight() const = 0;
KObject* GetParent() const; [[nodiscard]] KObject* GetParent() const;
private: private:
KObject* Parent; KObject* Parent;
}; };

View File

@ -10,11 +10,11 @@ namespace KapitanGame
public: public:
KExit(const KVector2D& position, const KTexture& texture) KExit(const KVector2D& position, const KTexture& texture)
: KObject(position, texture), : KObject(position, texture),
Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f) Collider(this, static_cast<float>(texture.GetWidth()), static_cast<float>(texture.GetHeight()))
{ {
} }
const KCollider* GetCollider() const override; [[nodiscard]] const KCollider* GetCollider() const override;
private: private:
KRect Collider; KRect Collider;
}; };

View File

@ -1,5 +1,7 @@
#include "KFont.h" #include "KFont.h"
#include <sstream>
#include "KTexture.h" #include "KTexture.h"
namespace KapitanGame namespace KapitanGame
@ -48,16 +50,49 @@ namespace KapitanGame
KTexture KFont::GetTextTexture(const std::string& text, const SDL_Color textColor, SDL_Renderer* renderer) const KTexture KFont::GetTextTexture(const std::string& text, const SDL_Color textColor, SDL_Renderer* renderer) const
{ {
KTexture texture; KTexture texture;
SDL_Surface* textSurface = TTF_RenderText_Solid(Font, text.c_str(), textColor); constexpr int spacing = 1;
if (textSurface == nullptr) int width, height = width = 0;
std::istringstream inputText;
inputText.str(text);
for(std::string line; std::getline(inputText, line);)
{
int w, h;
TTF_SizeText(Font, line.c_str(), &w, &h);
if (w > width) width = w;
height += w+spacing;
}
if (height > 0)
height -= spacing;
inputText.clear();
inputText.seekg(0);
SDL_Surface* textureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 8, SDL_PIXELFORMAT_INDEX8);
{
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()); printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
} }
else else
{ {
texture.LoadFromSurface(textSurface, renderer); SDL_Rect destRect{0, y, textSurface->w, textSurface->h};
SDL_BlitSurface(textSurface, nullptr, textureSurface, &destRect);
y += textSurface->h + spacing;
SDL_FreeSurface(textSurface); SDL_FreeSurface(textSurface);
} }
}
texture.LoadFromSurface(textureSurface, renderer);
SDL_FreeSurface(textureSurface);
return texture; return texture;
} }

View File

@ -11,18 +11,13 @@
#include "KCamera.h" #include "KCamera.h"
#include "KCirclePawn.h" #include "KCirclePawn.h"
#include "KExit.h" #include "KExit.h"
#include "KRectPawn.h"
#include "KTexture.h" #include "KTexture.h"
#include "KTile.h" #include "KTile.h"
#include "KVector2d.h" #include "KVector2d.h"
#include "KWall.h" #include "KWall.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace KapitanGame { 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 //Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) if (SDL_Init(SDL_INIT_VIDEO) < 0)
@ -109,7 +104,10 @@ namespace KapitanGame {
if (mapWidth < static_cast<float>(line.length() * Constants::TILE_WIDTH)) if (mapWidth < static_cast<float>(line.length() * Constants::TILE_WIDTH))
mapWidth = static_cast<float>(line.length()) * Constants::TILE_WIDTH; mapWidth = static_cast<float>(line.length()) * Constants::TILE_WIDTH;
for (auto i = 0ull; i < line.length(); ++i) { for (auto i = 0ull; i < line.length(); ++i) {
KVector2D position{ static_cast<float>(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2) , static_cast<float>(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) }; KVector2D position{
static_cast<float>(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2), // NOLINT(bugprone-integer-division)
static_cast<float>(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) // NOLINT(bugprone-integer-division)
};
switch (line[i]) switch (line[i])
{ {
case '#': case '#':
@ -150,7 +148,7 @@ namespace KapitanGame {
break; break;
} }
PlayerControllers.emplace_back(std::make_shared<KPlayerController>(player, this)); PlayerControllers.emplace_back(std::make_shared<KPlayerController>(player));
PlayerControllers.back()->SetupInputBindings(Input); PlayerControllers.back()->SetupInputBindings(Input);
} }
Textures.emplace("wall.bmp", KTexture()); Textures.emplace("wall.bmp", KTexture());
@ -168,11 +166,8 @@ namespace KapitanGame {
Fonts.erase("PressStart2P-Regular"); Fonts.erase("PressStart2P-Regular");
success = false; 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 (std::ifstream configFile("config.json"); configFile.fail()) {
if (configFile.fail()) {
printf("Failed to load config.json!\n"); printf("Failed to load config.json!\n");
success = false; success = false;
} }
@ -218,8 +213,7 @@ namespace KapitanGame {
camera.Update(Pawns, Map); camera.Update(Pawns, Map);
VelocityTextureDirty = true; SettingsTextTextureDirty = true;
GravityTextureDirty = true;
Time = PreviousTime = SDL_GetTicks(); Time = PreviousTime = SDL_GetTicks();
printf("\n"); printf("\n");
@ -229,7 +223,7 @@ namespace KapitanGame {
{ {
PreviousTime = Time; PreviousTime = Time;
Time = SDL_GetTicks(); Time = SDL_GetTicks();
float deltaTime = (Time - PreviousTime) * 0.001f; float deltaTime = static_cast<float>(Time - PreviousTime) * 0.001f;
Input.HandleInputPreEvents(); Input.HandleInputPreEvents();
@ -255,31 +249,28 @@ namespace KapitanGame {
if (devMode >= 1) { if (devMode >= 1) {
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2)) if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2))
{ {
CollisionEnabled = !CollisionEnabled; Settings.CollisionEnabled = !Settings.CollisionEnabled;
} }
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F3)) if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F3))
{ {
Settings.JumpVelocity -= 0.1f; Settings.MaxJumpHeight -= 0.1f;
if (Settings.JumpVelocity < 0) Settings.JumpVelocity = 0; //Settings.SetMaxJumpHeight(Settings.GetMaxJumpHeight() - 0.1f);
VelocityTextureDirty = true; SettingsTextTextureDirty = true;
} }
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F4)) if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F4))
{ {
Settings.JumpVelocity += 0.1f; Settings.MaxJumpHeight += 0.1f;
if (Settings.JumpVelocity > Constants::MAX_JUMP_VELOCITY) Settings.JumpVelocity = Constants::MAX_JUMP_VELOCITY; SettingsTextTextureDirty = true;
VelocityTextureDirty = true;
} }
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F5)) if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F5))
{ {
Settings.Gravity -= 0.1f; Settings.HorizontalDistanceToMaxJumpHeight -= 0.1f;
if (Settings.Gravity < 0) Settings.Gravity = 0; SettingsTextTextureDirty = true;
GravityTextureDirty = true;
} }
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F6)) if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F6))
{ {
Settings.Gravity += 0.1f; Settings.HorizontalDistanceToMaxJumpHeight += 0.1f;
if (Settings.Gravity > Constants::MAX_GRAVITY) Settings.Gravity = Constants::MAX_GRAVITY; SettingsTextTextureDirty = true;
GravityTextureDirty = true;
} }
} }
@ -291,7 +282,7 @@ namespace KapitanGame {
if (!Playing) break; if (!Playing) break;
pawn->MovementStep(deltaTime); pawn->MovementStep(deltaTime);
} }
if (CollisionEnabled) { if (Settings.CollisionEnabled) {
for (const auto& pawn : Pawns) { for (const auto& pawn : Pawns) {
if (!Playing) break; if (!Playing) break;
pawn->CollisionDetectionStep(Objects); pawn->CollisionDetectionStep(Objects);
@ -309,14 +300,19 @@ namespace KapitanGame {
camera.Update(Pawns, Map); camera.Update(Pawns, Map);
} }
if (VelocityTextureDirty) { //if (SettingsTextTextureDirty) {
Textures.insert_or_assign("Text_Velocity", Fonts["PressStart2P-Regular"].GetTextTexture(Utils::StringFormat("Velocity: %f", Settings.JumpVelocity), { 0,0,0,0xFF }, Renderer)); Textures.insert_or_assign("Text_Settings", Fonts["PressStart2P-Regular"].GetTextTexture(
VelocityTextureDirty = false; 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",
if (GravityTextureDirty) { static_cast<float>(Settings.MaxJumpHeight),
Textures.insert_or_assign("Text_Gravity", Fonts["PressStart2P-Regular"].GetTextTexture(Utils::StringFormat("Gravity: %f", Settings.Gravity), { 0,0,0,0xFF }, Renderer)); static_cast<float>(Settings.HorizontalDistanceToMaxJumpHeight),
GravityTextureDirty = false; static_cast<float>(Settings.JumpInitialVelocity),
} static_cast<float>(Settings.Gravity),
Pawns.back()->GetPosition().X,
Pawns.back()->GetPosition().Y), {0, 0, 0, 0xFF},
Renderer));
//SettingsTextTextureDirty = false;
//}
if (!Playing) if (!Playing)
@ -326,16 +322,6 @@ namespace KapitanGame {
LoadLevel(); LoadLevel();
debugCamera.SetDebug(Map); debugCamera.SetDebug(Map);
camera.Update(Pawns, Map); camera.Update(Pawns, Map);
if (ShowWinner)
{
for (auto i : Utils::KPlayerIterator())
{
Scores[static_cast<int>(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; Playing = true;
continue; continue;
} }
@ -355,22 +341,10 @@ namespace KapitanGame {
for (const auto& pawn : Pawns) { for (const auto& pawn : Pawns) {
pawn->Render(Renderer, cameraInUse); 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) { if (devMode >= 1) {
Textures["Text_Velocity"].Render(Renderer, 10.f, 25.f); Textures["Text_Settings"].Render(Renderer, 10.f, 25.f);
Textures["Text_Gravity"].Render(Renderer, 10.f, 30.f + Textures["Text_Velocity"].GetHeight());
} }
if (devMode >= 2) if (devMode >= 2)
{ {

View File

@ -20,7 +20,6 @@ namespace KapitanGame {
public: public:
KGame(); KGame();
~KGame(); ~KGame();
void Win(KPlayer player);
KGame(const KGame& other) = delete; KGame(const KGame& other) = delete;
KGame(KGame&& other) noexcept = delete; KGame(KGame&& other) noexcept = delete;
KGame& operator=(const KGame& other) = delete; KGame& operator=(const KGame& other) = delete;
@ -40,12 +39,9 @@ namespace KapitanGame {
uint32_t Time; uint32_t Time;
uint32_t PreviousTime; uint32_t PreviousTime;
SDL_FRect Map; SDL_FRect Map;
bool CollisionEnabled = true;
bool ShowWinner = false;
std::weak_ptr<KObject> Exit; std::weak_ptr<KObject> Exit;
KSettings Settings; KSettings Settings;
bool VelocityTextureDirty; bool SettingsTextTextureDirty = true;
bool GravityTextureDirty;
bool LoadLevel(); bool LoadLevel();
bool LoadMedia(); bool LoadMedia();
@ -53,7 +49,6 @@ namespace KapitanGame {
int LvlCounter = 1; int LvlCounter = 1;
bool Playing = true; bool Playing = true;
uint32_t RestartTick = -1; uint32_t RestartTick = -1;
short Scores[static_cast<int>(KPlayer::Player2) + 1] = { 0,0 };
}; };
} }

View File

@ -121,6 +121,7 @@ namespace KapitanGame {
} }
} }
break; break;
default: break;
} }
} }

View File

@ -1,5 +1,7 @@
#include "KObject.h" #include "KObject.h"
#include <SDL_render.h>
#include "KCamera.h" #include "KCamera.h"
namespace KapitanGame namespace KapitanGame
@ -13,7 +15,7 @@ namespace KapitanGame
void KObject::Render(SDL_Renderer* renderer, const KCamera& camera) const 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 KVector2D KObject::GetPosition() const

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <SDL_render.h>
#include "KTexture.h" #include "KTexture.h"
#include "KVector2d.h" #include "KVector2d.h"
@ -15,8 +16,8 @@ namespace KapitanGame
KObject(const KVector2D& position, const KTexture& texture); KObject(const KVector2D& position, const KTexture& texture);
virtual ~KObject() = default; virtual ~KObject() = default;
void Render(SDL_Renderer* renderer, const KCamera& camera) const; void Render(SDL_Renderer* renderer, const KCamera& camera) const;
KVector2D GetPosition() const; [[nodiscard]] KVector2D GetPosition() const;
virtual const KCollider* GetCollider() const = 0; [[nodiscard]] virtual const KCollider* GetCollider() const = 0;
const int Id; const int Id;
static std::atomic<int> IdCounter; static std::atomic<int> IdCounter;
protected: protected:

View File

@ -68,6 +68,10 @@ namespace KapitanGame
CanDoubleJump = true; CanDoubleJump = true;
HasJumped = false; HasJumped = false;
} }
if (separationVector.Y > 0)
{
Velocity.Y = 0;
}
} }
void KPawn::AddXMovementInput(const float& input) void KPawn::AddXMovementInput(const float& input)
@ -77,8 +81,8 @@ namespace KapitanGame
void KPawn::StopJump() { void KPawn::StopJump() {
if (!CanJump) { if (!CanJump) {
if (Velocity.Y < -Settings->ShortJumpVelocity()) if (Velocity.Y < -Settings->ShortJumpVelocity)
Velocity.Y = -Settings->ShortJumpVelocity(); Velocity.Y = -Settings->ShortJumpVelocity;
} }
} }
@ -90,12 +94,12 @@ namespace KapitanGame
if (CanJump) { if (CanJump) {
CanJump = false; CanJump = false;
HasJumped = true; HasJumped = true;
Velocity.Y = -Settings->JumpVelocity; Velocity.Y = -Settings->JumpInitialVelocity;
} }
else if (HasJumped && CanDoubleJump) else if (HasJumped && CanDoubleJump)
{ {
CanDoubleJump = false; CanDoubleJump = false;
Velocity.Y = -Settings->JumpVelocity; Velocity.Y = -Settings->JumpInitialVelocity;
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <SDL_rect.h>
#include <unordered_map> #include <unordered_map>
#include "KObject.h" #include "KObject.h"
@ -7,7 +8,7 @@
namespace KapitanGame namespace KapitanGame
{ {
struct KSettings; class KSettings;
class KPlayerController; class KPlayerController;
class KPawn : public KObject class KPawn : public KObject

View File

@ -1,6 +1,5 @@
#include "KPlayerController.h" #include "KPlayerController.h"
#include "KGame.h"
#include "KInput.h" #include "KInput.h"
namespace KapitanGame { namespace KapitanGame {

View File

@ -4,15 +4,13 @@
#include "KVector2d.h" #include "KVector2d.h"
namespace KapitanGame { namespace KapitanGame {
class KGame;
class KInput; class KInput;
class KPlayerController : public std::enable_shared_from_this<KPlayerController> class KPlayerController : public std::enable_shared_from_this<KPlayerController>
{ {
public: public:
KPlayerController(const KPlayer player, KGame* const game) explicit KPlayerController(const KPlayer player)
: Player(player), : Player(player)
Game(game)
{ {
} }
@ -21,7 +19,6 @@ namespace KapitanGame {
void StartJump(); void StartJump();
void StopJump(); void StopJump();
void Update(float deltaTime); void Update(float deltaTime);
void NotifyWin() const;
void Possess(KPawn* pawn); void Possess(KPawn* pawn);
void UnPossess(); void UnPossess();
const KPlayer& GetPlayer() const; const KPlayer& GetPlayer() const;
@ -29,7 +26,6 @@ namespace KapitanGame {
KVector2D Input{ 0.f, 0.f }; KVector2D Input{ 0.f, 0.f };
const KPlayer Player; const KPlayer Player;
KPawn* Pawn{}; KPawn* Pawn{};
KGame* Game;
bool InputStartJump{}; bool InputStartJump{};
bool InputStopJump{}; bool InputStopJump{};
}; };

View File

@ -15,20 +15,21 @@ namespace KapitanGame {
Height(height) 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); static KVector2D GetSeparationVector(float left, float right, float top, float bottom);
bool IsCollision(const KCollider* other) const override; bool IsCollision(const KCollider* other) const override;
KVector2D GetSeparationVector(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: private:
KVector2D GetSeparationVector(const KCircle* other) const; KVector2D GetSeparationVector(const KCircle* other) const;
KVector2D GetSeparationVector(const KRect* other) const; KVector2D GetSeparationVector(const KRect* other) const;
bool IsCollision(const KCircle* other) const; bool IsCollision(const KCircle* other) const;
float GetLeft() const; [[nodiscard]] float GetLeft() const;
float GetRight() const; [[nodiscard]] float GetRight() const;
float GetBottom() const; [[nodiscard]] float GetBottom() const;
float GetTop() const; [[nodiscard]] float GetTop() const;
bool IsCollision(const KRect* other) const; bool IsCollision(const KRect* other) const;
float Width; float Width;
float Height; float Height;

View File

@ -1,9 +1,98 @@
#include "KSettings.h" #include "KSettings.h"
#include <algorithm>
#include <cmath>
#include "Constants.h"
namespace KapitanGame 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;
} }
} }

View File

@ -1,14 +1,37 @@
#pragma once #pragma once
#include "Constants.h" #include "Property.h"
namespace KapitanGame namespace KapitanGame
{ {
struct KSettings class KSettings final
{ {
float Gravity = Constants::GRAVITY; float MaxJumpHeightValue;
float JumpVelocity = Constants::JUMP_SPEED; 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<float, KSettings> MaxJumpHeight, HorizontalDistanceToMaxJumpHeight;
const ReadOnlyProperty<float, KSettings> TimeToMaxHeight, Gravity, JumpInitialVelocity, ShortJumpVelocity;
const Property<bool, KSettings> 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();
}; };
} }

View File

@ -1,5 +1,7 @@
#include "KTexture.h" #include "KTexture.h"
#include <SDL_render.h>
namespace KapitanGame { namespace KapitanGame {
KTexture::KTexture() : Texture(nullptr), Width(0), Height(0) KTexture::KTexture() : Texture(nullptr), Width(0), Height(0)
{ {

View File

@ -0,0 +1,54 @@
#pragma once
namespace KapitanGame
{
template <class T, class C>
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 T, class C>
class Property : public ReadOnlyProperty<T,C> {
void(C::* Setter)(T);
public:
Property() : ReadOnlyProperty(), Setter() {}
Property(C* owner, T(C::* getter)(), void(C::* setter)(T)) : ReadOnlyProperty<T, C>(owner,getter), Setter(setter) {}
void Set(T value) const {
(this->Owner->*Setter)(value);
}
const Property<T, C>& operator = (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(value);
return *this;
}
const Property<T, C>& operator -= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() - value);
return *this;
}
const Property<T, C>& operator += (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() + value);
return *this;
}
const Property<T, C>& operator *= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() * value);
return *this;
}
const Property<T, C>& operator /= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() / value);
return *this;
}
};
}