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

View File

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

View File

@ -1,7 +1,7 @@
#pragma once
namespace KapitanGame {
namespace Constants {
namespace KapitanGame::Constants
{
constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 3 (Lab 11-12)";
//Analog joystick dead zone
constexpr int JOYSTICK_DEAD_ZONE = 8000;
@ -15,8 +15,7 @@ namespace KapitanGame {
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 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;
}
}

View File

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

View File

@ -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 };
};

View File

@ -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;
};

View File

@ -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<float>(texture.GetWidth()), static_cast<float>(texture.GetHeight()))
{
}
const KCollider* GetCollider() const override;
[[nodiscard]] const KCollider* GetCollider() const override;
private:
KRect Collider;
};

View File

@ -1,5 +1,7 @@
#include "KFont.h"
#include <sstream>
#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);)
{
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());
}
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);
}
}
texture.LoadFromSurface(textureSurface, renderer);
SDL_FreeSurface(textureSurface);
return texture;
}

View File

@ -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<float>(line.length() * Constants::TILE_WIDTH))
mapWidth = static_cast<float>(line.length()) * Constants::TILE_WIDTH;
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])
{
case '#':
@ -150,7 +148,7 @@ namespace KapitanGame {
break;
}
PlayerControllers.emplace_back(std::make_shared<KPlayerController>(player, this));
PlayerControllers.emplace_back(std::make_shared<KPlayerController>(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<float>(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<float>(Settings.MaxJumpHeight),
static_cast<float>(Settings.HorizontalDistanceToMaxJumpHeight),
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)
@ -326,16 +322,6 @@ namespace KapitanGame {
LoadLevel();
debugCamera.SetDebug(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;
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)
{

View File

@ -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<KObject> 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<int>(KPlayer::Player2) + 1] = { 0,0 };
};
}

View File

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

View File

@ -1,5 +1,7 @@
#include "KObject.h"
#include <SDL_render.h>
#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

View File

@ -1,5 +1,6 @@
#pragma once
#include <atomic>
#include <SDL_render.h>
#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<int> IdCounter;
protected:

View File

@ -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;
}
}
}

View File

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

View File

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

View File

@ -4,15 +4,13 @@
#include "KVector2d.h"
namespace KapitanGame {
class KGame;
class KInput;
class KPlayerController : public std::enable_shared_from_this<KPlayerController>
{
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{};
};

View File

@ -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;

View File

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

View File

@ -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<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 <SDL_render.h>
namespace KapitanGame {
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;
}
};
}