diff --git a/2dgk_7/readme.txt b/2dgk_7/readme.txt
index 74e0672..2bceeec 100644
--- a/2dgk_7/readme.txt
+++ b/2dgk_7/readme.txt
@@ -1,6 +1,6 @@
-IDE: Microsoft Visual Studio 2019
+IDE: Microsoft Visual Studio 2022
Kompilator: Microsoft Visual C++
-Biblioteki: SDL2
+Biblioteki: SDL2, SDL2_ttf, nlohmann-json
Przetestowane pady: DualSense, DualShock 3 (ze sterownikiem/wrapperem XInputowym ScpToolkit), telefon Android (ze sterownikiem/wrapperem XInputowym HandyGamePad).
diff --git a/2dgk_zad3/2dgk_zad3.sln b/2dgk_zad3/2dgk_zad3.sln
new file mode 100644
index 0000000..5090cd3
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31729.503
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{423520C9-0301-4445-99D4-078B2842C600}") = "2dgk_zad3", "2dgk_zad3\2dgk_zad3.vcxproj", "{710B7A8E-21B0-4956-9B5B-F92A42AF86EA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Debug|x64.ActiveCfg = Debug|x64
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Debug|x64.Build.0 = Debug|x64
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Debug|x86.ActiveCfg = Debug|Win32
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Debug|x86.Build.0 = Debug|Win32
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Release|x64.ActiveCfg = Release|x64
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Release|x64.Build.0 = Release|x64
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Release|x86.ActiveCfg = Release|Win32
+ {710B7A8E-21B0-4956-9B5B-F92A42AF86EA}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F6AE8D48-1DC7-43D1-9855-F4AD626525B1}
+ EndGlobalSection
+EndGlobal
diff --git a/2dgk_zad3/2dgk_zad3/2dgk_zad3.rc b/2dgk_zad3/2dgk_zad3/2dgk_zad3.rc
new file mode 100644
index 0000000..abaf653
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/2dgk_zad3.rc
@@ -0,0 +1,101 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Polish (Poland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK)
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "041504b0"
+ BEGIN
+ VALUE "CompanyName", "Michał Leśniak"
+ VALUE "FileDescription", "A simple game"
+ VALUE "FileVersion", "1.0.0.1"
+ VALUE "InternalName", "2dgk_zad3.exe"
+ VALUE "LegalCopyright", "Copyright (C) 2021 Michał Leśniak"
+ VALUE "OriginalFilename", "2dgk_zad3.exe"
+ VALUE "ProductName", "2DKG_ZAD3"
+ VALUE "ProductVersion", "1.0.0.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x415, 1200
+ END
+END
+
+#endif // Polish (Poland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj
new file mode 100644
index 0000000..2ea6dca
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj
@@ -0,0 +1,250 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {710b7a8e-21b0-4956-9b5b-f92a42af86ea}
+ My2dgk_zad3
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ vcpkg_installed\x86-windows\x86-windows\include\SDL2
+
+
+ Console
+ true
+ vcpkg_installed\x86-windows\x86-windows\debug\lib\manual-link;%(AdditionalLibraryDirectories)
+ SDL2maind.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ vcpkg_installed\x86-windows\x86-windows\include\SDL2
+
+
+ Console
+ true
+ true
+ true
+ vcpkg_installed\x86-windows\x86-windows\lib\manual-link;%(AdditionalLibraryDirectories)
+ SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ vcpkg_installed\x64-windows\x64-windows\include\SDL2
+ stdcpp17
+
+
+ Console
+ true
+ vcpkg_installed\x64-windows\x64-windows\debug\lib\manual-link;%(AdditionalLibraryDirectories)
+ SDL2maind.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ vcpkg_installed\x64-windows\x64-windows\include\SDL2
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ vcpkg_installed\x64-windows\x64-windows\lib\manual-link;%(AdditionalLibraryDirectories)
+ SDL2main.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+
+
\ 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
new file mode 100644
index 0000000..8571c7c
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/2dgk_zad3.vcxproj.filters
@@ -0,0 +1,149 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/Constants.h b/2dgk_zad3/2dgk_zad3/Constants.h
new file mode 100644
index 0000000..3de0b55
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/Constants.h
@@ -0,0 +1,20 @@
+#pragma once
+namespace KapitanGame {
+ namespace Constants {
+ constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 2 (Lab 7-8)";
+ //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 = 200.f;
+ constexpr float JUMP_SHORT_SPEED = 100.f;
+ constexpr float GRAVITY = 200.f;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/Controllers.h b/2dgk_zad3/2dgk_zad3/Controllers.h
new file mode 100644
index 0000000..6df735f
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/Controllers.h
@@ -0,0 +1,9 @@
+#pragma once
+namespace KapitanGame {
+ enum class Controllers : int {
+ Controller1,
+ Controller2,
+ Controller3,
+ Controller4
+ };
+}
diff --git a/2dgk_zad3/2dgk_zad3/GamePad.h b/2dgk_zad3/2dgk_zad3/GamePad.h
new file mode 100644
index 0000000..4d8990f
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/GamePad.h
@@ -0,0 +1,8 @@
+#pragma once
+#include
+namespace KapitanGame {
+ struct GamePad {
+ bool Buttons[SDL_CONTROLLER_BUTTON_MAX];
+ int Axis[SDL_CONTROLLER_AXIS_MAX];
+ };
+}
diff --git a/2dgk_zad3/2dgk_zad3/KActionBind.h b/2dgk_zad3/2dgk_zad3/KActionBind.h
new file mode 100644
index 0000000..f2cb2de
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KActionBind.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "KPlayer.h"
+#include "KPlayerController.h"
+
+namespace KapitanGame {
+ ;
+ enum class InputState : int {
+ Pressed,
+ Released,
+ Hold
+ };
+ struct KActionBind {
+ KActionBind(std::string name, const InputState expectedInputState, const std::shared_ptr& controllerObject, const KPlayerCommand command, const KPlayer player) :
+ Name(std::move(name)), ExpectedInputState(expectedInputState), ControllerObject(controllerObject), Command(command), Player(player) {}
+ std::string Name;
+ InputState ExpectedInputState;
+ std::weak_ptr ControllerObject;
+ KPlayerCommand Command;
+ KPlayer Player;
+ };
+ struct KAxisBind
+ {
+ KAxisBind(std::string name, const std::shared_ptr& controllerObject, const KPlayerAxisCommand command, const KPlayer player) :
+ Name(std::move(name)), ControllerObject(controllerObject), AxisCommand(command), Player(player) {}
+ std::string Name;
+ std::weak_ptr ControllerObject;
+ KPlayerAxisCommand AxisCommand;
+ KPlayer Player;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KCamera.cpp b/2dgk_zad3/2dgk_zad3/KCamera.cpp
new file mode 100644
index 0000000..f287972
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCamera.cpp
@@ -0,0 +1,46 @@
+#include "KCamera.h"
+
+#include "KPawn.h"
+#include "Utils.h"
+
+namespace KapitanGame
+{
+ const SDL_FRect& KCamera::GetViewport() const
+ {
+ return Viewport;
+ }
+
+ float KCamera::GetScale() const
+ {
+ return Scale;
+ }
+
+ const KVector2D& KCamera::GetFocusPoint() const
+ {
+ return FocusPoint;
+ }
+
+ void KCamera::Update(const std::vector>& pawns, const SDL_FRect& map)
+ {
+ FocusPoint = { 0.f,0.f };
+ for(const auto& pawn : pawns) {
+ FocusPoint += pawn->GetPosition();
+ }
+ FocusPoint *= 1.f / static_cast(pawns.size());
+ Viewport.x = Utils::Clamp(FocusPoint.X - Viewport.w / 2.f, 0.f, map.w - Viewport.w);
+ Viewport.y = Utils::Clamp(FocusPoint.Y - Viewport.h / 2.f, 0.f, map.h - Viewport.h);
+ PlayArea.x = Utils::Clamp(FocusPoint.X - PlayArea.w / 2.f, static_cast(-Constants::WINDOW_DEAD_ZONE), map.w + static_cast(Constants::WINDOW_DEAD_ZONE));
+ PlayArea.y = Utils::Clamp(FocusPoint.Y - PlayArea.h / 2.f, static_cast(-Constants::WINDOW_DEAD_ZONE), map.h + static_cast(Constants::WINDOW_DEAD_ZONE));
+ }
+
+ void KCamera::SetDebug(const SDL_FRect& map)
+ {
+ Viewport = { 0,0,Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT };
+ Scale = Constants::SCREEN_RATIO > 1.f ? Constants::SCREEN_HEIGHT * 1.f / map.h : Constants::SCREEN_WIDTH * 1.f / map.w;
+ }
+
+ const SDL_FRect& KCamera::GetPlayArea() const
+ {
+ return PlayArea;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KCamera.h b/2dgk_zad3/2dgk_zad3/KCamera.h
new file mode 100644
index 0000000..357223a
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCamera.h
@@ -0,0 +1,43 @@
+#pragma once
+#include
+#include
+#include
+
+#include "Constants.h"
+#include "KVector2d.h"
+
+namespace KapitanGame
+{
+ class KPawn;
+
+ class KCamera
+ {
+ public:
+ explicit KCamera(const SDL_FRect& map)
+ : Viewport({
+ (map.w - Constants::SCREEN_WIDTH) / 2.f, (map.h - Constants::SCREEN_HEIGHT) / 2.f,
+ Constants::SCREEN_WIDTH * 1.f,
+ Constants::SCREEN_HEIGHT * 1.f
+ }), PlayArea({
+ 0, 0,
+ Constants::SCREEN_WIDTH - Constants::WINDOW_DEAD_ZONE,
+ Constants::SCREEN_HEIGHT - Constants::WINDOW_DEAD_ZONE
+ }), FocusPoint(Viewport.x + Viewport.w / 2, Viewport.y + Viewport.h / 2),
+ Scale(1.f)
+ {
+ }
+
+ const SDL_FRect& GetViewport() const;
+ float GetScale() const;
+ const KVector2D& GetFocusPoint() const;
+ void Update(const std::vector>& pawns, const SDL_FRect& map);
+ void SetDebug(const SDL_FRect& map);
+ const SDL_FRect& GetPlayArea() const;
+ private:
+ SDL_FRect Viewport;
+ SDL_FRect PlayArea;
+ KVector2D FocusPoint;
+ float Scale;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KCircle.cpp b/2dgk_zad3/2dgk_zad3/KCircle.cpp
new file mode 100644
index 0000000..51d562c
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCircle.cpp
@@ -0,0 +1,111 @@
+#include "KCircle.h"
+
+#include
+
+#include "KRect.h"
+#include "Utils.h"
+
+namespace KapitanGame {
+
+ bool KCircle::IsCollision(const KCircle* other) const {
+ return (GetParent()->GetPosition() - other->GetParent()->GetPosition()).Length() < Radius + other->Radius;
+ }
+
+ bool KCircle::IsCollision(const KCollider* other) const
+ {
+ const auto circle = dynamic_cast(other);
+ if (circle != nullptr)
+ return IsCollision(circle);
+
+
+ const auto rect = dynamic_cast(other);
+ if (rect != nullptr)
+ return IsCollision(rect);
+
+ throw std::runtime_error("unsupported shape");
+ }
+
+ KVector2D KCircle::GetSeparationVector(const KCollider* other) const
+ {
+ const auto circle = dynamic_cast(other);
+ if (circle != nullptr)
+ return GetSeparationVector(circle);
+
+ const auto rect = dynamic_cast(other);
+ if (rect != nullptr)
+ return GetSeparationVector(rect);
+
+ throw std::runtime_error("unsupported shape");
+ }
+
+ bool KCircle::IsCollision(const KRect* other) const {
+ const auto f = KVector2D(Utils::Clamp(GetParent()->GetPosition().X, other->GetParent()->GetPosition().X - other->GetWidth() / 2, other->GetParent()->GetPosition().X + other->GetWidth() / 2),
+ Utils::Clamp(GetParent()->GetPosition().Y, other->GetParent()->GetPosition().Y - other->GetHeight() / 2, other->GetParent()->GetPosition().Y + other->GetHeight() / 2));
+
+ return (GetParent()->GetPosition() - f).Length() < Radius;
+ }
+
+ KVector2D KCircle::GetSeparationVector(const KCircle* other) const {
+ const KVector2D centerDiff = GetParent()->GetPosition() - other->GetParent()->GetPosition();
+ const float centerDiffLength = centerDiff.Length();
+ return centerDiff / centerDiffLength * (Radius + other->Radius - centerDiffLength);
+ }
+
+ KVector2D KCircle::GetSeparationVector(const KRect* other) const {
+ const float l = other->GetParent()->GetPosition().X - other->GetWidth() / 2;
+ const float r = other->GetParent()->GetPosition().X + other->GetWidth() / 2;
+ const float t = other->GetParent()->GetPosition().Y - other->GetHeight() / 2;
+ const float b = other->GetParent()->GetPosition().Y + other->GetHeight() / 2;
+ const auto f = KVector2D(Utils::Clamp(GetParent()->GetPosition().X, l, r),
+ Utils::Clamp(GetParent()->GetPosition().Y, t, b));
+
+ if (GetParent()->GetPosition() == f) {
+ const auto left = GetParent()->GetPosition().X - l + Radius;
+ const auto right = r - GetParent()->GetPosition().X + Radius;
+ const auto top = GetParent()->GetPosition().Y - t + Radius;
+ const auto bottom = b - GetParent()->GetPosition().Y + Radius;
+ return KRect::GetSeparationVector(left, right, top, bottom);
+ }
+ return (GetParent()->GetPosition() - f) / (GetParent()->GetPosition() - f).Length() * (Radius - (GetParent()->GetPosition() - f).Length());
+ }
+
+ KVector2D KCircle::GetSeparationVector(const SDL_FRect& map) const {
+ KVector2D separationVector{ 0.f,0.f };
+ if (GetParent()->GetPosition().X - map.x - Radius < 0)
+ {
+ separationVector.X += -(GetParent()->GetPosition().X - map.x - Radius);
+ }
+ if (GetParent()->GetPosition().X + Radius - (map.x + map.w) > 0)
+ {
+ separationVector.X += -(GetParent()->GetPosition().X - (map.x+map.w) + Radius);
+ }
+ if (GetParent()->GetPosition().Y - Radius - map.y < 0) {
+ separationVector.Y += -(GetParent()->GetPosition().Y - map.y - Radius);
+ }
+ if (GetParent()->GetPosition().Y + Radius - (map.y + map.h) > 0) {
+ separationVector.Y += -(GetParent()->GetPosition().Y - (map.y + map.h) + Radius);
+ }
+ return separationVector;
+ }
+
+ float KCircle::GetWidth() const
+ {
+ return Radius * 2;
+ }
+
+ float KCircle::GetHeight() const
+ {
+ return Radius * 2;
+ }
+
+ KCircle::KCircle(KObject* parent, const float radius): KCollider(parent),
+ Radius(radius)
+ {
+ }
+
+ float KCircle::GetRadius() const {
+ return Radius;
+ }
+
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KCircle.h b/2dgk_zad3/2dgk_zad3/KCircle.h
new file mode 100644
index 0000000..a4db204
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCircle.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+
+#include "KCollider.h"
+#include "KVector2d.h"
+
+namespace KapitanGame {
+ class KRect;
+
+ class KCircle final : public KCollider
+ {
+ public:
+ KCircle(KObject* parent, const float radius);
+ float GetRadius() const;
+ private:
+ KVector2D GetSeparationVector(const KCircle* other) const;
+ KVector2D GetSeparationVector(const KRect* other) const;
+ bool IsCollision(const KCircle* other) const;
+ bool IsCollision(const KRect* other) const;
+ 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;
+ private:
+ float Radius{ 1.f };
+ };
+}
+
+
diff --git a/2dgk_zad3/2dgk_zad3/KCirclePawn.cpp b/2dgk_zad3/2dgk_zad3/KCirclePawn.cpp
new file mode 100644
index 0000000..4e8a2dc
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCirclePawn.cpp
@@ -0,0 +1,15 @@
+#include "KCirclePawn.h"
+
+namespace KapitanGame
+{
+ KCirclePawn::KCirclePawn(const KVector2D& position, const KTexture& texture,
+ const std::shared_ptr& playerController) : KPawn(position, texture, playerController),
+ Collider(this, static_cast(texture.GetWidth())/2.0f)
+ {
+ }
+
+ const KCollider* KCirclePawn::GetCollider() const
+ {
+ return &Collider;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KCirclePawn.h b/2dgk_zad3/2dgk_zad3/KCirclePawn.h
new file mode 100644
index 0000000..9ffac03
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCirclePawn.h
@@ -0,0 +1,18 @@
+#pragma once
+#include "KCircle.h"
+#include "KPawn.h"
+
+namespace KapitanGame
+{
+ class KCirclePawn final :public KPawn
+ {
+ public:
+ KCirclePawn(const KVector2D& position, const KTexture& texture,
+ const std::shared_ptr& playerController);
+
+ const KCollider* GetCollider() const override;
+ private:
+ KCircle Collider;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KCollider.cpp b/2dgk_zad3/2dgk_zad3/KCollider.cpp
new file mode 100644
index 0000000..feaa9fe
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCollider.cpp
@@ -0,0 +1,34 @@
+#include "KCollider.h"
+
+namespace KapitanGame {
+ KCollider::KCollider(const KCollider& other) = default;
+
+ KCollider::KCollider(KCollider&& other) noexcept: Parent(other.Parent)
+ {
+ }
+
+ KCollider& KCollider::operator=(const KCollider& other)
+ {
+ if (this == &other)
+ return *this;
+ Parent = other.Parent;
+ return *this;
+ }
+
+ KCollider& KCollider::operator=(KCollider&& other) noexcept
+ {
+ if (this == &other)
+ return *this;
+ Parent = other.Parent;
+ return *this;
+ }
+
+ KCollider::KCollider(KObject* parent): Parent(parent)
+ {
+ }
+
+ KObject* KCollider::GetParent() const
+ {
+ return Parent;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KCollider.h b/2dgk_zad3/2dgk_zad3/KCollider.h
new file mode 100644
index 0000000..77e8e07
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KCollider.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include
+
+#include "KObject.h"
+#include "KVector2d.h"
+
+namespace KapitanGame {
+
+ class KCollider
+ {
+ public:
+ KCollider(const KCollider& other);
+
+ KCollider(KCollider&& other) noexcept;
+
+ KCollider& operator=(const KCollider& other);
+
+ KCollider& operator=(KCollider&& other) noexcept;
+
+ explicit KCollider(KObject* parent);
+
+ 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;
+ private:
+ KObject* Parent;
+ };
+}
+
+
diff --git a/2dgk_zad3/2dgk_zad3/KExit.cpp b/2dgk_zad3/2dgk_zad3/KExit.cpp
new file mode 100644
index 0000000..c015f3b
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KExit.cpp
@@ -0,0 +1,9 @@
+#include "KExit.h"
+
+namespace KapitanGame
+{
+ const KCollider* KExit::GetCollider() const
+ {
+ return &Collider;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KExit.h b/2dgk_zad3/2dgk_zad3/KExit.h
new file mode 100644
index 0000000..60c5d45
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KExit.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "KObject.h"
+#include "KRect.h"
+
+namespace KapitanGame
+{
+ class KExit final :
+ public KObject
+ {
+ public:
+ KExit(const KVector2D& position, const KTexture& texture)
+ : KObject(position, texture),
+ Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f)
+ {
+ }
+
+ const KCollider* GetCollider() const override;
+ private:
+ KRect Collider;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KFont.cpp b/2dgk_zad3/2dgk_zad3/KFont.cpp
new file mode 100644
index 0000000..520fede
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KFont.cpp
@@ -0,0 +1,97 @@
+#include "KFont.h"
+
+#include "KTexture.h"
+
+namespace KapitanGame
+{
+ KFont::KFont()
+ = default;
+
+ KFont::~KFont()
+ {
+ Free();
+ }
+
+ KFont::KFont(KFont&& other) noexcept : Font(other.Font)
+ {
+ other.Font = nullptr;
+ }
+
+ KFont& KFont::operator=(KFont&& other) noexcept
+ {
+ Font = other.Font;
+ other.Font = nullptr;
+ return *this;
+ }
+
+ bool KFont::LoadFromFile(const std::string& path, const int ptSize)
+ {
+ bool success = true;
+ Font = TTF_OpenFont(path.c_str(), ptSize);
+ if (Font == nullptr)
+ {
+ printf("Failed to load %s font! SDL_ttf Error: %s\n", path.c_str(), TTF_GetError());
+ success = false;
+ }
+ return success;
+ }
+
+ void KFont::Free()
+ {
+ if (Font != nullptr)
+ {
+ TTF_CloseFont(Font);
+ Font = nullptr;
+ }
+ }
+
+ KTexture KFont::GetTextTexture(const std::string& text, const SDL_Color textColor, SDL_Renderer* renderer) const
+ {
+ KTexture texture;
+ SDL_Surface* textSurface = TTF_RenderText_Blended(Font, text.c_str(), textColor);
+ if (textSurface == nullptr)
+ {
+ printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
+ }
+ else
+ {
+ texture.LoadFromSurface(textSurface, renderer);
+ SDL_FreeSurface(textSurface);
+ }
+ return texture;
+ }
+
+ KTexture KFont::GetTextWithOutlineTexture(const std::string& text, const SDL_Color fgColor, const SDL_Color bgColor,
+ const int outlineSize, SDL_Renderer* renderer) const
+ {
+ KTexture texture;
+ const int originalOutlineSize = TTF_GetFontOutline(Font);
+
+ if (SDL_Surface* fgSurface = TTF_RenderText_Blended(Font, text.c_str(), fgColor); fgSurface == nullptr)
+ {
+ printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
+ }
+ else
+ {
+ TTF_SetFontOutline(Font, outlineSize);
+ SDL_Surface* bgSurface = TTF_RenderText_Blended(Font, text.c_str(), bgColor);
+ TTF_SetFontOutline(Font, originalOutlineSize);
+ if (bgSurface == nullptr)
+ {
+ printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
+ }
+ else
+ {
+ SDL_Rect rect = { outlineSize, outlineSize, fgSurface->w, fgSurface->h };
+
+ /* blit text onto its outline */
+ SDL_SetSurfaceBlendMode(fgSurface, SDL_BLENDMODE_BLEND);
+ SDL_BlitSurface(fgSurface, nullptr, bgSurface, &rect);
+ texture.LoadFromSurface(bgSurface, renderer);
+ SDL_FreeSurface(bgSurface);
+ }
+ SDL_FreeSurface(fgSurface);
+ }
+ return texture;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KFont.h b/2dgk_zad3/2dgk_zad3/KFont.h
new file mode 100644
index 0000000..20e8e92
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KFont.h
@@ -0,0 +1,37 @@
+#pragma once
+#include
+#include
+
+namespace KapitanGame {
+ //Font wrapper class
+ class KTexture;
+ class KFont {
+ public:
+ KFont();
+
+ ~KFont();
+
+ KFont(const KFont& other) = delete;
+
+ KFont(KFont&& other) noexcept;
+
+ KFont& operator=(const KFont& other) = delete;
+
+ KFont& operator=(KFont&& other) noexcept;
+
+ //Loads image at specified path
+ bool LoadFromFile(const std::string& path, int ptSize);
+
+ //Deallocates Font
+ void Free();
+
+ KTexture GetTextTexture(const std::string& text, SDL_Color textColor, SDL_Renderer* renderer) const;
+ KTexture GetTextWithOutlineTexture(const std::string& text, SDL_Color fgColor, SDL_Color bgColor, int outlineSize, SDL_Renderer* renderer) const;
+
+ private:
+ //The actual hardware font
+ TTF_Font* Font{};
+ };
+
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KGame.cpp b/2dgk_zad3/2dgk_zad3/KGame.cpp
new file mode 100644
index 0000000..d8df2be
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KGame.cpp
@@ -0,0 +1,362 @@
+#include "KGame.h"
+#include "SDL.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include "Utils.h"
+#include "Constants.h"
+#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()
+ {
+ //Initialize SDL
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ {
+ throw std::runtime_error(Utils::StringFormat("SDL could not initialize! SDL_Error: %s", SDL_GetError()));
+ }
+ //Set texture filtering to linear
+ if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
+ {
+ printf("Warning: Linear texture filtering not enabled!\n");
+ }
+
+ Input.Init();
+
+ if (TTF_Init() < 0)
+ {
+ throw std::runtime_error(Utils::StringFormat("SDL_TTF could not initialize! TTF_Error: %s", TTF_GetError()));
+ }
+
+ //Create window
+ Window = SDL_CreateWindow(Constants::WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+ Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
+ if (Window == nullptr)
+ {
+ throw std::runtime_error(Utils::StringFormat("Window could not be created! SDL_Error: %s", SDL_GetError()));
+ }
+ //Create renderer for window
+ Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_ACCELERATED);
+ if (Renderer == nullptr)
+ {
+ throw std::runtime_error(
+ Utils::StringFormat("Renderer could not be created! SDL Error: %s", SDL_GetError()));
+ }
+ //Initialize renderer color
+ SDL_SetRenderDrawColor(Renderer, 0, 0xFF, 0, 0xFF);
+ }
+
+ KGame::~KGame() {
+ //Free loaded images
+ Textures.clear();
+ Objects.clear();
+ Pawns.clear();
+ PlayerControllers.clear();
+ Fonts.clear();
+ TTF_Quit();
+ Input.Free();
+
+ //Destroy window
+ SDL_DestroyRenderer(Renderer);
+ SDL_DestroyWindow(Window);
+ Window = nullptr;
+ Renderer = nullptr;
+
+ //Quit SDL subsystems
+ SDL_Quit();
+ }
+
+ bool KGame::LoadLevel()
+ {
+ bool success = true;
+ Objects.clear();
+ FreePositions.clear();
+ /*std::ifstream levelFile;
+ levelFile.open("assets/levels/level" + std::to_string(LvlCounter) + ".txt");
+ if (levelFile.fail())
+ {
+ printf("Failed to load assets/levels/level%d.txt!\n", LvlCounter);
+ success = false;
+ }
+ else
+ {
+ int y = 0;
+ float mapWidth = 0;
+ std::string line;
+ while (std::getline(levelFile, line)) {
+ 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) };
+ switch (line[i])
+ {
+ case '#':
+ Objects.emplace(std::make_pair(static_cast(i), y), std::make_shared(position, Textures["wall.bmp"]));
+ break;
+ case ' ':
+ FreePositions.emplace_back(position);
+ break;
+ default:
+ break;
+ }
+ }
+ ++y;
+ }
+ const auto mapHeight = static_cast(y * Constants::TILE_HEIGHT);
+ levelFile.close();
+ Map = { 0,0,mapWidth,mapHeight };
+ }*/
+ Map = { 0,0,Constants::SCREEN_WIDTH,Constants::SCREEN_HEIGHT };
+ return success;
+ }
+
+ void KGame::LoadPlayerPawn()
+ {
+ Pawns.clear();
+ KVector2D StartPosition{ 0.f, 0.f };
+ Pawns.emplace_back(std::make_shared(StartPosition, Textures["P1.bmp"], PlayerControllers[static_cast(KPlayer::Player1)]));
+ PlayerControllers[static_cast(KPlayer::Player1)]->Possess(Pawns.back().get());
+ }
+
+ bool KGame::LoadMedia()
+ {
+ //Loading success flag
+ bool success = true;
+
+ for (auto player : Utils::KPlayerIterator())
+ {
+ std::string filename = "P" + std::to_string(static_cast(player) + 1) + ".bmp";
+ Textures.emplace(filename, KTexture());
+ if (!Textures[filename].LoadFromFile("assets/textures/" + filename, Renderer))
+ {
+ Textures.erase(filename);
+ printf("Failed to load player texture image!\n");
+ success = false;
+ break;
+ }
+
+ PlayerControllers.emplace_back(std::make_shared(player, this));
+ PlayerControllers.back()->SetupInputBindings(Input);
+ }
+ Textures.emplace("wall.bmp", KTexture());
+ if (!Textures["wall.bmp"].LoadFromFile("assets/textures/wall.bmp", Renderer))
+ {
+ printf("Failed to load wall texture image!\n");
+ Textures.erase("wall.bmp");
+ success = false;
+ }
+
+ Fonts.emplace("PressStart2P-Regular", KFont());
+ if (!Fonts["PressStart2P-Regular"].LoadFromFile("assets/fonts/PressStart2P-Regular.ttf", 72))
+ {
+ printf("Failed to load PressStart2P-Regular font!\n");
+ 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()) {
+ printf("Failed to load config.json!\n");
+ success = false;
+ }
+ else {
+ nlohmann::json configJson;
+ configFile >> configJson;
+ configFile.close();
+ for (auto& player : configJson["Input"].items()) {
+ const auto playerEnum = Utils::GetPlayerFromString(player.key());
+ for (auto& axisMapping : player.value()["AxisMappings"]) {
+ Input.AddAxisMapping(axisMapping["AxisName"].get(), axisMapping["Scale"].get(), axisMapping["Key"].get(), playerEnum);
+ }
+ for (auto& actionMapping : player.value()["ActionMappings"]) {
+ Input.AddActionMapping(actionMapping["ActionName"].get(), actionMapping["Key"].get(), playerEnum);
+ }
+ }
+ }
+ if (!LoadLevel())
+ success = false;
+ return success;
+ }
+
+ int KGame::Run(int argc, char* args[])
+ {
+ //Load media
+ if (!LoadMedia())
+ {
+ printf("Failed to load media!\n");
+ }
+ else
+ {
+ //Main loop flag
+ bool quit = false;
+
+ //Event handler
+ SDL_Event e;
+
+ KCamera camera(Map);
+ KCamera debugCamera(Map);
+ debugCamera.SetDebug(Map);
+
+ bool debug = false;
+
+ LoadPlayerPawn();
+ camera.Update(Pawns, Map);
+
+ Time = PreviousTime = SDL_GetTicks();
+ printf("\n");
+
+ //While application is running
+ while (!quit)
+ {
+ PreviousTime = Time;
+ Time = SDL_GetTicks();
+ float deltaTime = (Time - PreviousTime) * 0.001f;
+
+ Input.HandleInputPreEvents();
+
+ //Handle events on queue
+ while (SDL_PollEvent(&e))
+ {
+ //User requests quit
+ if (e.type == SDL_QUIT)
+ {
+ quit = true;
+ continue;
+ }
+ Input.HandleEvent(e);
+ }
+
+ Input.HandleInputPostEvents(Playing);
+
+ if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F1))
+ {
+ debug = !debug;
+ }
+ if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2))
+ {
+ CollisionEnabled = !CollisionEnabled;
+ }
+
+ if (Playing) {
+ for (const auto& pc : PlayerControllers) {
+ pc->Update(deltaTime);
+ }
+ for (const auto& pawn : Pawns) {
+ if (!Playing) break;
+ pawn->MovementStep(deltaTime);
+ }
+ if (CollisionEnabled) {
+ for (const auto& pawn : Pawns) {
+ if (!Playing) break;
+ pawn->CollisionDetectionStep(Objects);
+ }
+ }
+ for (const auto& pawn : Pawns) {
+ if (!Playing) break;
+ pawn->CollisionDetectionWithMapStep(Map);
+ }
+ for (const auto& pawn : Pawns) {
+ if (!Playing) break;
+ pawn->CollisionDetectionWithMapStep(camera.GetPlayArea());
+ }
+
+ camera.Update(Pawns, Map);
+
+ }
+
+ if (!Playing)
+ {
+ if (Time > RestartTick)
+ {
+ LoadLevel();
+ LoadPlayerPawn();
+ 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;
+ }
+ }
+
+
+ //Clear screen
+ SDL_SetRenderDrawColor(Renderer, 66, 135, 245, 0xFF);
+ SDL_RenderClear(Renderer);
+
+ const auto& cameraInUse = debug ? debugCamera : camera;
+
+
+ if (Playing) {
+ for (const auto& object : Objects)
+ object.second->Render(Renderer, cameraInUse);
+ 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 (debug)
+ {
+ SDL_SetRenderDrawColor(Renderer, 0x00, 0x00, 0x00, 0xFF);
+ SDL_RenderDrawLineF(Renderer, 0, Constants::SCREEN_HEIGHT / 2.f, Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT / 2.f);
+ SDL_RenderDrawLineF(Renderer, Constants::SCREEN_WIDTH / 2.f, 0, Constants::SCREEN_WIDTH / 2.f, Constants::SCREEN_HEIGHT);
+ SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
+
+ SDL_RenderDrawPointF(Renderer, camera.GetFocusPoint().X * debugCamera.GetScale(), camera.GetFocusPoint().Y * debugCamera.GetScale());
+ SDL_SetRenderDrawColor(Renderer, 0xFF, 0x00, 0x00, 0xFF);
+ SDL_FRect debugViewport = { camera.GetViewport().x * debugCamera.GetScale(),
+ camera.GetViewport().y * debugCamera.GetScale(),
+ camera.GetViewport().w * debugCamera.GetScale(),
+ camera.GetViewport().h * debugCamera.GetScale() };
+ SDL_RenderDrawRectF(Renderer, &debugViewport);
+ SDL_FRect debug2Viewport = { camera.GetPlayArea().x * debugCamera.GetScale(),
+ camera.GetPlayArea().y * debugCamera.GetScale(),
+ camera.GetPlayArea().w * debugCamera.GetScale(),
+ camera.GetPlayArea().h * debugCamera.GetScale() };
+ SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
+ SDL_RenderDrawRectF(Renderer, &debug2Viewport);
+ }
+
+ //Update screen
+ SDL_RenderPresent(Renderer);
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KGame.h b/2dgk_zad3/2dgk_zad3/KGame.h
new file mode 100644
index 0000000..bc2dc56
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KGame.h
@@ -0,0 +1,58 @@
+#pragma once
+#include
+
+#include "KTexture.h"
+#include
+#include
+
+#include "KFont.h"
+#include "KInput.h"
+#include "Utils.h"
+
+
+namespace KapitanGame {
+ class KExit;
+ class KObject;
+
+ class KGame
+ {
+ public:
+ KGame();
+ ~KGame();
+ void Win(KPlayer player);
+ KGame(const KGame& other) = delete;
+ KGame(KGame&& other) noexcept = delete;
+ KGame& operator=(const KGame& other) = delete;
+ KGame& operator=(KGame&& other) noexcept = delete;
+ int Run(int argc, char* args[]);
+ private:
+ SDL_Window* Window = nullptr;
+
+ SDL_Renderer* Renderer = nullptr;
+
+ std::unordered_map, std::shared_ptr, Utils::PairHash> Objects;
+ std::vector> Pawns;
+ std::vector> PlayerControllers;
+ std::unordered_map Textures;
+ std::unordered_map Fonts;
+ std::vector FreePositions;
+ KInput Input;
+ uint32_t Time;
+ uint32_t PreviousTime;
+ SDL_FRect Map;
+ bool CollisionEnabled = true;
+ bool ShowWinner = false;
+ std::weak_ptr Exit;
+
+ bool LoadLevel();
+ void LoadPlayerPawn();
+ bool LoadMedia();
+
+ 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
new file mode 100644
index 0000000..0b5544b
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KInput.cpp
@@ -0,0 +1,306 @@
+#include "KInput.h"
+#include "Constants.h"
+
+#include
+#include
+
+namespace KapitanGame {
+ KInput::KInput() : GamePadsCount(0), Initialized(false)
+ {
+ }
+
+ void KInput::Init() {
+ if (Initialized) return;
+ if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) != 1)
+ SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
+
+ const int nJoysticks = SDL_NumJoysticks();
+ GamePadsCount = 0;
+
+ // Count how many controllers there are
+ for (int i = 0; i < nJoysticks; i++)
+ if (SDL_IsGameController(i))
+ GamePadsCount++;
+
+ // If we have some controllers attached
+ if (GamePadsCount > 0)
+ {
+ for (int i = 0; i < GamePadsCount; i++)
+ {
+ // Open the controller and add it to our list
+ SDL_GameController* pad = SDL_GameControllerOpen(i);
+ if (SDL_GameControllerGetAttached(pad) == 1)
+ ConnectedControllers.push_back(pad);
+ else
+ printf("SDL_GetError() = %s\n", SDL_GetError());
+ }
+ SDL_GameControllerEventState(SDL_ENABLE);
+ }
+
+ // Vectors are empty to begin with, this sets their size
+ ControllerInputs.resize(GamePadsCount);
+ LastControllerInputs.resize(GamePadsCount);
+
+ // Set the status of the controllers to "nothing is happening"
+ for (int i = 0; i < GamePadsCount; i++) {
+ for (int a = 0; a < SDL_CONTROLLER_AXIS_MAX; a++) {
+ ControllerInputs[i].Axis[a] = 0;
+ LastControllerInputs[i].Axis[a] = 0;
+ }
+ for (int b = 0; b < SDL_CONTROLLER_BUTTON_MAX; b++) {
+ ControllerInputs[i].Buttons[b] = false;
+ LastControllerInputs[i].Buttons[b] = false;
+ }
+ }
+ Initialized = true;
+ }
+
+ void KInput::Free() {
+ for (const auto& pad : ConnectedControllers) {
+ SDL_GameControllerClose(pad);
+ }
+ ConnectedControllers.clear();
+ Actions.clear();
+ }
+
+ void KInput::HandleInputPreEvents() {
+ for (int i = 0; i < GamePadsCount; i++) {
+ for (int a = 0; a < SDL_CONTROLLER_AXIS_MAX; a++) {
+ LastControllerInputs[i].Axis[a] = ControllerInputs[i].Axis[a];
+ }
+ for (int b = 0; b < SDL_CONTROLLER_BUTTON_MAX; b++) {
+ LastControllerInputs[i].Buttons[b] = ControllerInputs[i].Buttons[b];
+ }
+ }
+ LastKeyboardInputs = KeyboardInputs;
+ }
+ void KInput::HandleInputPostEvents(const bool processInput) {
+ int size = 0;
+ const Uint8* currentKeyStates = SDL_GetKeyboardState(&size);
+ KeyboardInputs = std::vector(currentKeyStates, currentKeyStates + size);
+ if (processInput) {
+ ProcessActions();
+ ProcessAxes();
+ }
+ }
+ void KInput::HandleEvent(const SDL_Event& event) {
+ switch (event.type) {
+ // This happens when a device is added
+ // A future improvement is to cope with new controllers being plugged in
+ // when the game is running
+ case SDL_CONTROLLERDEVICEADDED:
+ printf("DEVICEADDED cdevice.which = %d\n", event.cdevice.which);
+ break;
+
+ // If a controller button is pressed
+ case SDL_CONTROLLERBUTTONDOWN:
+ // Cycle through the controllers
+ for (int i = 0; i < GamePadsCount; i++) {
+ // Looking for the button that was pressed
+ if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ConnectedControllers[i]))) {
+ // So the relevant state can be updated
+ ControllerInputs[i].Buttons[event.cbutton.button] = true;
+ }
+ }
+ break;
+
+ // Do the same for releasing a button
+ case SDL_CONTROLLERBUTTONUP:
+ for (int i = 0; i < GamePadsCount; i++) {
+ if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ConnectedControllers[i]))) {
+ ControllerInputs[i].Buttons[event.cbutton.button] = false;
+ }
+ }
+ break;
+
+ // And something similar for axis motion
+ case SDL_CONTROLLERAXISMOTION:
+ for (int i = 0; i < GamePadsCount; i++) {
+ if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ConnectedControllers[i]))) {
+ ControllerInputs[i].Axis[event.caxis.axis] = event.caxis.value;
+ }
+ }
+ break;
+ }
+ }
+
+ void KInput::BindAction(const std::string& name, InputState expectedInputState,
+ const std::shared_ptr& controllerObject,
+ KPlayerCommand command, KPlayer player) {
+ Actions.emplace_back(name, expectedInputState, controllerObject, command, player);
+ }
+
+ void KInput::BindAxis(const std::string& name, const std::shared_ptr& controllerObject, KPlayerAxisCommand command, KPlayer player)
+ {
+ Axes.emplace_back(name, controllerObject, command, player);
+ }
+
+ bool KInput::CheckAction(const std::string& name, const InputState expectedInputState, KPlayer player) {
+ const auto keyBindRange = KeyBinds[static_cast(player)].equal_range(name);
+ for (auto keyBind = keyBindRange.first; keyBind != keyBindRange.second; ++keyBind) {
+ switch (expectedInputState) {
+ case InputState::Pressed:
+ if (IsKeyboardButtonPressed(keyBind->second)) {
+ return true;
+ }
+ break;
+ case InputState::Released:
+ if (IsKeyboardButtonReleased(keyBind->second)) {
+ return true;
+ }
+ break;
+ case InputState::Hold:
+ if (IsKeyboardButtonHeld(keyBind->second)) {
+ return true;
+ }
+ break;
+ }
+ }
+
+ const auto buttonBindRange = ButtonBinds[static_cast(player)].equal_range(name);
+ for (auto buttonBind = buttonBindRange.first; buttonBind != buttonBindRange.second; ++buttonBind) {
+ switch (expectedInputState) {
+ case InputState::Pressed:
+ if (IsControllerButtonPressed(buttonBind->second.first, buttonBind->second.second)) {
+ return true;
+ }
+ break;
+ case InputState::Released:
+ if (IsControllerButtonReleased(buttonBind->second.first, buttonBind->second.second)) {
+ return true;
+ }
+ break;
+ case InputState::Hold:
+ if (IsControllerButtonHeld(buttonBind->second.first, buttonBind->second.second)) {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ void KInput::ProcessActions() {
+ for (auto& action : Actions) {
+ if (CheckAction(action.Name, action.ExpectedInputState, action.Player)) {
+ if (auto obj = action.ControllerObject.lock())
+ std::invoke(action.Command, obj);
+ }
+ }
+ }
+
+ void KInput::ProcessAxes()
+ {
+ for (auto& axis : Axes) {
+ if (auto obj = axis.ControllerObject.lock())
+ std::invoke(axis.AxisCommand, obj, GetAxisValue(axis.Name, axis.Player));
+ }
+ }
+
+ void KInput::AddAxisMapping(const std::string& name, const float& scale, const std::string& key, const KPlayer& player)
+ {
+ if (key.rfind("Gamepad", 0) == 0) {
+ const auto delimiterPosition = key.find('_', 7);
+ const auto controllerIndex = static_cast(std::stoi(key.substr(7, delimiterPosition)));
+ auto axis = key.substr(delimiterPosition + 1);
+ std::for_each(axis.begin(), axis.end(), [](char& c) {
+ c = ::tolower(c);
+ });
+ ControllerAxisBinds[static_cast(player)].emplace(name, KControllerAxisMapping(controllerIndex, SDL_GameControllerGetAxisFromString(axis.c_str()), scale));
+ }
+ else {
+ SDL_Scancode scanCode = SDL_GetScancodeFromName(key.c_str());
+ if (scanCode != SDL_SCANCODE_UNKNOWN) {
+ KeyAxisBinds[static_cast(player)].emplace(name, std::make_pair(scanCode, scale));
+ }
+ }
+ }
+
+ void KInput::AddActionMapping(const std::string& name, const std::string& key, const KPlayer& player)
+ {
+ if (key.rfind("Gamepad", 0) == 0) {
+ const auto delimiterPosition = key.find('_', 7);
+ const auto controllerIndex = static_cast(std::stoi(key.substr(7, delimiterPosition)));
+ auto button = key.substr(delimiterPosition + 1);
+ std::for_each(button.begin(), button.end(), [](char& c) {
+ c = ::tolower(c);
+ });
+ ButtonBinds[static_cast(player)].emplace(name, std::make_pair(controllerIndex, SDL_GameControllerGetButtonFromString(button.c_str())));
+ }
+ else {
+ SDL_Scancode scanCode = SDL_GetScancodeFromName(key.c_str());
+ if (scanCode != SDL_SCANCODE_UNKNOWN) {
+ KeyBinds[static_cast(player)].emplace(name, scanCode);
+ }
+ }
+ }
+
+ bool KInput::IsControllerButtonPressed(const Controllers controllerId, const SDL_GameControllerButton button) const
+ {
+ if (controllerId < Controllers::Controller1 || controllerId > static_cast(GamePadsCount - 1)) return false;
+
+ return ControllerInputs[static_cast(controllerId)].Buttons[button] && !LastControllerInputs[static_cast(controllerId)].Buttons[button];
+ }
+ bool KInput::IsControllerButtonReleased(const Controllers controllerId, const SDL_GameControllerButton button) const
+ {
+ if (controllerId < Controllers::Controller1 || controllerId > static_cast(GamePadsCount - 1)) return false;
+
+ return !ControllerInputs[static_cast(controllerId)].Buttons[button] && LastControllerInputs[static_cast(controllerId)].Buttons[button];
+ }
+
+ bool KInput::IsControllerButtonHeld(const Controllers controllerId, const SDL_GameControllerButton button) const
+ {
+ if (controllerId < Controllers::Controller1 || controllerId > static_cast(GamePadsCount - 1)) return false;
+
+ return ControllerInputs[static_cast(controllerId)].Buttons[button] && LastControllerInputs[static_cast(controllerId)].Buttons[button];
+ }
+
+ float KInput::GetControllerAxis(const Controllers controllerId, const SDL_GameControllerAxis axis) const
+ {
+ if (controllerId static_cast(GamePadsCount - 1)) return 0.0;
+
+ const int value = ControllerInputs[static_cast(controllerId)].Axis[axis];
+ if (std::abs(value) < Constants::JOYSTICK_DEAD_ZONE) return 0.0;
+
+ return static_cast(value) / 32768.0f;
+ }
+
+ bool KInput::IsKeyboardButtonPressed(const Uint8 scanCode) const
+ {
+ if (scanCode > KeyboardInputs.size() || scanCode > LastKeyboardInputs.size())
+ return false;
+ return KeyboardInputs[scanCode] && KeyboardInputs[scanCode] != LastKeyboardInputs[scanCode];
+ }
+
+ bool KInput::IsKeyboardButtonReleased(const Uint8 scanCode) const
+ {
+ if (scanCode > KeyboardInputs.size() || scanCode > LastKeyboardInputs.size())
+ return false;
+ return !KeyboardInputs[scanCode] && KeyboardInputs[scanCode] != LastKeyboardInputs[scanCode];
+ }
+
+ float KInput::GetAxisValue(const std::string& name, const KPlayer& player) const
+ {
+ float value = 0.f;
+ const auto keyAxisBindRange = KeyAxisBinds[static_cast(player)].equal_range(name);
+ for (auto keyAxisBind = keyAxisBindRange.first; keyAxisBind != keyAxisBindRange.second; ++keyAxisBind) {
+ if (IsKeyboardButtonHeld(keyAxisBind->second.first)) {
+ value += 1.0f * keyAxisBind->second.second;
+ }
+ }
+
+ const auto controllerAxisBindRange = ControllerAxisBinds[static_cast(player)].equal_range(name);
+ for (auto controllerAxisBind = controllerAxisBindRange.first; controllerAxisBind != controllerAxisBindRange.second; ++controllerAxisBind) {
+ value += GetControllerAxis(controllerAxisBind->second.Controller, controllerAxisBind->second.Axis) * controllerAxisBind->second.Scale;
+ }
+ return value;
+ }
+
+ bool KInput::IsKeyboardButtonHeld(const Uint8 scanCode) const
+ {
+ if (scanCode > KeyboardInputs.size())
+ return false;
+ return KeyboardInputs[scanCode];
+ }
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KInput.h b/2dgk_zad3/2dgk_zad3/KInput.h
new file mode 100644
index 0000000..4678c94
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KInput.h
@@ -0,0 +1,61 @@
+#pragma once
+#include
+#include
+#include
+
+#include "Controllers.h"
+#include "GamePad.h"
+#include "KActionBind.h"
+#include "KPlayer.h"
+
+namespace KapitanGame {
+ struct KControllerAxisMapping {
+ KControllerAxisMapping(const Controllers controller, const SDL_GameControllerAxis axis, const float scale) : Controller(controller), Axis(axis), Scale(scale) {}
+ Controllers Controller;
+ SDL_GameControllerAxis Axis;
+ float Scale;
+ };
+
+ class KInput {
+ std::vector ConnectedControllers;
+ std::vector ControllerInputs;
+ std::vector LastControllerInputs;
+ std::vector KeyboardInputs;
+ std::vector LastKeyboardInputs;
+ std::vector Actions;
+ std::vector Axes;
+ std::unordered_multimap KeyBinds[static_cast(KPlayer::Player2) + 1];
+ std::unordered_multimap> ButtonBinds[static_cast(KPlayer::Player2) + 1];
+ std::unordered_multimap ControllerAxisBinds[static_cast(KPlayer::Player2) + 1];
+ std::unordered_multimap> KeyAxisBinds[static_cast(KPlayer::Player2) + 1];
+ int GamePadsCount;
+ bool Initialized;
+
+ void ProcessActions();
+ void ProcessAxes();
+ public:
+ KInput();
+ void Init();
+ void Free();
+ void HandleInputPreEvents();
+ void HandleInputPostEvents(bool processInput);
+ void HandleEvent(const SDL_Event& event);
+ void BindAction(const std::string& name, InputState expectedInputState, const std::shared_ptr& controllerObject, KPlayerCommand command, KPlayer player);
+ void BindAxis(const std::string& name, const std::shared_ptr& controllerObject, KPlayerAxisCommand command, KPlayer player);
+ bool CheckAction(const std::string& name, InputState expectedInputState, KPlayer player);
+
+ void AddAxisMapping(const std::string& name, const float& scale, const std::string& key, const KPlayer& player);
+ void AddActionMapping(const std::string& name, const std::string& key, const KPlayer& player);
+
+ bool IsControllerButtonPressed(Controllers controllerId, SDL_GameControllerButton button) const;
+ bool IsControllerButtonReleased(Controllers controllerId, SDL_GameControllerButton button) const;
+ bool IsControllerButtonHeld(Controllers controllerId, SDL_GameControllerButton button) const;
+ float GetControllerAxis(Controllers controllerId, SDL_GameControllerAxis axis) const;
+ bool IsKeyboardButtonHeld(Uint8 scanCode) const;
+ bool IsKeyboardButtonPressed(Uint8 scanCode) const;
+ bool IsKeyboardButtonReleased(Uint8 scanCode) const;
+ float GetAxisValue(const std::string& name, const KPlayer& player) const;
+ };
+}
+
+
diff --git a/2dgk_zad3/2dgk_zad3/KObject.cpp b/2dgk_zad3/2dgk_zad3/KObject.cpp
new file mode 100644
index 0000000..d9cbed9
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KObject.cpp
@@ -0,0 +1,23 @@
+#include "KObject.h"
+
+#include "KCamera.h"
+
+namespace KapitanGame
+{
+ std::atomic KObject::IdCounter{ 0 };
+
+ KObject::KObject(const KVector2D& position, const KTexture& texture) :
+ Id(++IdCounter), Position(position), Texture(texture)
+ {
+ }
+
+ 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());
+ }
+
+ KVector2D KObject::GetPosition() const
+ {
+ return Position;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KObject.h b/2dgk_zad3/2dgk_zad3/KObject.h
new file mode 100644
index 0000000..14482fa
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KObject.h
@@ -0,0 +1,28 @@
+#pragma once
+#include
+
+#include "KTexture.h"
+#include "KVector2d.h"
+
+namespace KapitanGame
+{
+ class KCamera;
+ class KCollider;
+
+ class KObject
+ {
+ public:
+ 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;
+ const int Id;
+ static std::atomic IdCounter;
+ protected:
+ KVector2D Position{ 0.f, 0.f };
+ private:
+ const KTexture& Texture;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KPawn.cpp b/2dgk_zad3/2dgk_zad3/KPawn.cpp
new file mode 100644
index 0000000..344df6c
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KPawn.cpp
@@ -0,0 +1,86 @@
+#include "KPawn.h"
+
+#include
+#include
+#include
+
+#include "Constants.h"
+#include "KPlayerController.h"
+#include "KExit.h"
+
+namespace KapitanGame
+{
+ void KPawn::CollisionDetectionStep(const std::unordered_map, std::shared_ptr, Utils::PairHash>& objects)
+ {
+ if (GetCollider() == nullptr) return;
+
+ const auto xPos = static_cast(GetPosition().X / Constants::TILE_WIDTH);
+ const auto yPos = static_cast(GetPosition().Y / Constants::TILE_HEIGHT);
+
+ for (const auto& [oX, oY] : std::initializer_list>{ {0, 0}, {-1,0}, {1,0}, {0,-1}, {0,1}, {-1,-1}, {1,1}, {1,-1}, {-1,1} })
+ {
+ try {
+ const auto& other = objects.at({ xPos + oX, yPos + oY });
+ if (other->GetCollider() == nullptr) continue;
+ if (other->Id == Id) continue;
+ if (GetCollider()->IsCollision(other->GetCollider())) {
+ if (typeid(*other) == typeid(KExit)) {
+ if (const auto pc = PlayerController.lock()) {
+ //pc->NotifyWin();
+ }
+ return;
+ }
+ const auto separationVector = GetCollider()->GetSeparationVector(other->GetCollider());
+
+ Position += separationVector;
+ if (separationVector.Y < 0)
+ {
+ Velocity.Y = 0;
+ Grounded = true;
+ }
+ }
+ }
+ catch (std::out_of_range&)
+ {
+ }
+ }
+ }
+
+ void KPawn::MovementStep(const float& timeStep)
+ {
+ Position.X += Velocity.X * timeStep;
+ Position.Y += Velocity.Y * timeStep + 1.f / 2.f * Constants::GRAVITY * timeStep * timeStep;
+ Velocity.Y += Constants::GRAVITY * timeStep;
+ }
+
+ void KPawn::CollisionDetectionWithMapStep(const SDL_FRect& map)
+ {
+ const auto separationVector = GetCollider()->GetSeparationVector(map);
+ Position += separationVector;
+ if (separationVector.Y < 0)
+ {
+ Velocity.Y = 0;
+ Grounded = true;
+ }
+ }
+
+ void KPawn::AddXMovementInput(const float& input)
+ {
+ Velocity.X = input * Constants::SPEED * (1 - Constants::SMOOTH) + Velocity.X * Constants::SMOOTH;
+ }
+
+ void KPawn::StopJump() {
+ if (!Grounded) {
+ if (Velocity.Y < -Constants::JUMP_SHORT_SPEED)
+ Velocity.Y = -Constants::JUMP_SHORT_SPEED;
+ }
+ }
+
+ void KPawn::StartJump() {
+ if (Grounded) {
+ Grounded = false;
+ Velocity.Y = -Constants::JUMP_SPEED;
+ }
+ }
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KPawn.h b/2dgk_zad3/2dgk_zad3/KPawn.h
new file mode 100644
index 0000000..e37867e
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KPawn.h
@@ -0,0 +1,33 @@
+#pragma once
+#include
+#include
+
+#include "KObject.h"
+#include "Utils.h"
+
+namespace KapitanGame
+{
+ class KPlayerController;
+
+ class KPawn : public KObject
+ {
+ public:
+ KPawn(const KVector2D& position, const KTexture& texture,
+ const std::shared_ptr& playerController)
+ : KObject(position, texture),
+ PlayerController(playerController)
+ {
+ }
+ void CollisionDetectionStep(const std::unordered_map, std::shared_ptr, Utils::PairHash>& objects);
+ void MovementStep(const float& timeStep);
+ void CollisionDetectionWithMapStep(const SDL_FRect& map);
+ void AddXMovementInput(const float& input);
+ void StopJump();
+ void StartJump();
+ private:
+ const std::weak_ptr PlayerController;
+ KVector2D Velocity{ 0.f, 0.f };
+ bool Grounded;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KPlayer.h b/2dgk_zad3/2dgk_zad3/KPlayer.h
new file mode 100644
index 0000000..f5af9a2
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KPlayer.h
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace KapitanGame {
+ enum class KPlayer : int {
+ Player1,
+ Player2
+ };
+}
diff --git a/2dgk_zad3/2dgk_zad3/KPlayerController.cpp b/2dgk_zad3/2dgk_zad3/KPlayerController.cpp
new file mode 100644
index 0000000..e7010d7
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KPlayerController.cpp
@@ -0,0 +1,56 @@
+#include "KPlayerController.h"
+
+#include "KGame.h"
+#include "KInput.h"
+
+namespace KapitanGame {
+ void KPlayerController::SetupInputBindings(KInput& input)
+ {
+ input.BindAxis("MoveX", shared_from_this(), &KPlayerController::MoveXAxis, Player);
+ input.BindAction("Jump", InputState::Pressed, shared_from_this(), &KPlayerController::StartJump, Player);
+ input.BindAction("Jump", InputState::Released, shared_from_this(), &KPlayerController::StopJump, Player);
+ }
+
+ void KPlayerController::MoveXAxis(const float axis)
+ {
+ Input.X += axis;
+ }
+
+ void KPlayerController::StartJump() {
+ InputStartJump = true;
+ }
+
+ void KPlayerController::StopJump() {
+ InputStopJump = true;
+ }
+
+ void KPlayerController::Update(float deltaTime)
+ {
+ Input.Normalize();
+ if (Pawn != nullptr) {
+ Pawn->AddXMovementInput(Input.X);
+ if (InputStartJump)
+ Pawn->StartJump();
+ if (InputStopJump)
+ Pawn->StopJump();
+ }
+ Input *= 0;
+ InputStartJump = false;
+ InputStopJump = false;
+ }
+
+ void KPlayerController::Possess(KPawn* pawn)
+ {
+ Pawn = pawn;
+ }
+
+ void KPlayerController::UnPossess()
+ {
+ Pawn = nullptr;
+ }
+
+ const KPlayer& KPlayerController::GetPlayer() const
+ {
+ return Player;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KPlayerController.h b/2dgk_zad3/2dgk_zad3/KPlayerController.h
new file mode 100644
index 0000000..3b1913c
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KPlayerController.h
@@ -0,0 +1,40 @@
+#pragma once
+#include "KPawn.h"
+#include "KPlayer.h"
+#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)
+ {
+ }
+
+ void SetupInputBindings(KInput& input);
+ void MoveXAxis(float axis);
+ void StartJump();
+ void StopJump();
+ void Update(float deltaTime);
+ void NotifyWin() const;
+ void Possess(KPawn* pawn);
+ void UnPossess();
+ const KPlayer& GetPlayer() const;
+ private:
+ KVector2D Input{ 0.f, 0.f };
+ const KPlayer Player;
+ KPawn* Pawn{};
+ KGame* Game;
+ bool InputStartJump{};
+ bool InputStopJump{};
+ };
+ typedef void (KPlayerController::* KPlayerCommand)();
+ typedef void (KPlayerController::* KPlayerAxisCommand)(float input);
+}
+
+
diff --git a/2dgk_zad3/2dgk_zad3/KRect.cpp b/2dgk_zad3/2dgk_zad3/KRect.cpp
new file mode 100644
index 0000000..8a815f7
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KRect.cpp
@@ -0,0 +1,134 @@
+#include "KRect.h"
+
+#include "KCircle.h"
+#include "Utils.h"
+
+namespace KapitanGame {
+
+ float KRect::GetWidth() const {
+ return Width;
+ }
+
+ float KRect::GetHeight() const {
+ return Height;
+ }
+
+ KVector2D KRect::GetSeparationVector(const float left, const float right, const float top, const float bottom) {
+ const auto x = left < right ? -left : right;
+ const auto y = top < bottom ? -top : bottom;
+ auto vX = x;
+ auto vY = y;
+ if (fabs(x) < fabs(y))
+ vY = 0;
+ if (fabs(x) > fabs(y))
+ vX = 0;
+ return { vX, vY };
+ }
+
+ KVector2D KRect::GetSeparationVector(const KCircle* other) const {
+ const float l = GetLeft();
+ const float r = GetRight();
+ const float t = GetTop();
+ const float b = GetBottom();
+ const auto f = KVector2D(Utils::Clamp(other->GetParent()->GetPosition().X, l, r),
+ Utils::Clamp(other->GetParent()->GetPosition().Y, t, b));
+
+ if (other->GetParent()->GetPosition() == f) {
+ const auto left = other->GetParent()->GetPosition().X - l + other->GetRadius();
+ const auto right = r - other->GetParent()->GetPosition().X + other->GetRadius();
+ const auto top = other->GetParent()->GetPosition().Y - t + other->GetRadius();
+ const auto bottom = b - other->GetParent()->GetPosition().Y + other->GetRadius();
+ return GetSeparationVector(left, right, top, bottom) * -1.f;
+ }
+ return (other->GetParent()->GetPosition() - f) / (other->GetParent()->GetPosition() - f).Length() * (other->GetRadius() - (other->GetParent()->GetPosition() - f).Length()) * 1.f;
+ }
+
+ KVector2D KRect::GetSeparationVector(const KRect* other) const {
+ const auto left = GetRight() - other->GetLeft();
+ const auto right = other->GetRight() - GetLeft();
+ const auto top = GetBottom() - other->GetTop();
+ const auto bottom = other->GetBottom() - GetTop();
+
+ return GetSeparationVector(left, right, top, bottom);
+ }
+
+ bool KRect::IsCollision(const KCircle* other) const {
+ const auto f = KVector2D(Utils::Clamp(other->GetParent()->GetPosition().X, GetLeft(), GetRight()),
+ Utils::Clamp(other->GetParent()->GetPosition().Y, GetTop(), GetBottom()));
+
+ return (other->GetParent()->GetPosition() - f).Length() < other->GetRadius();
+ }
+
+ float KRect::GetLeft() const
+ {
+ return GetParent()->GetPosition().X - Width / 2;
+ }
+
+ float KRect::GetRight() const
+ {
+ return GetParent()->GetPosition().X + Width / 2;
+ }
+
+ float KRect::GetBottom() const
+ {
+ return GetParent()->GetPosition().Y + Height / 2;
+ }
+
+ float KRect::GetTop() const
+ {
+ return GetParent()->GetPosition().Y - Height / 2;
+ }
+
+ bool KRect::IsCollision(const KRect* other) const {
+ return GetRight() >= other->GetLeft()
+ && other->GetRight() >= GetLeft()
+ && GetBottom() >= other->GetTop()
+ && other->GetBottom() >= GetTop();
+ }
+
+ bool KRect::IsCollision(const KCollider* other) const
+ {
+ const auto circle = dynamic_cast(other);
+ if (circle != nullptr)
+ return IsCollision(circle);
+
+ const auto rect = dynamic_cast(other);
+ if (rect != nullptr)
+ return IsCollision(rect);
+
+ throw std::runtime_error("unsupported shape");
+ }
+
+ KVector2D KRect::GetSeparationVector(const KCollider* other) const
+ {
+ const auto circle = dynamic_cast(other);
+ if (circle != nullptr)
+ return GetSeparationVector(circle);
+
+ const auto rect = dynamic_cast(other);
+ if (rect != nullptr)
+ return GetSeparationVector(rect);
+
+ throw std::runtime_error("unsupported shape");
+ }
+
+ KVector2D KRect::GetSeparationVector(const SDL_FRect& map) const
+ {
+ KVector2D separationVector{ 0.f,0.f };
+ if (GetParent()->GetPosition().X - map.x - GetWidth() / 2 < 0)
+ {
+ separationVector.X += -(GetParent()->GetPosition().X - map.x - GetWidth() / 2);
+ }
+ if (GetParent()->GetPosition().X + GetWidth() / 2 - (map.x + map.w) > 0)
+ {
+ separationVector.X += -(GetParent()->GetPosition().X - (map.x + map.w) + GetWidth() / 2);
+ }
+ if (GetParent()->GetPosition().Y - GetHeight() / 2 - map.y < 0) {
+ separationVector.Y += -(GetParent()->GetPosition().Y - map.y - GetHeight() / 2);
+ }
+ if (GetParent()->GetPosition().Y + GetHeight() / 2 - (map.y + map.h) > 0) {
+ separationVector.Y += -(GetParent()->GetPosition().Y - (map.y + map.h) + GetHeight() / 2);
+ }
+ return separationVector;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KRect.h b/2dgk_zad3/2dgk_zad3/KRect.h
new file mode 100644
index 0000000..66cd3ca
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KRect.h
@@ -0,0 +1,38 @@
+#pragma once
+#include
+
+#include "KCollider.h"
+
+namespace KapitanGame {
+ class KCircle;
+
+ class KRect final : public KCollider
+ {
+ public:
+ KRect(KObject* parent, const float width, const float height)
+ : KCollider(parent),
+ Width(width),
+ Height(height)
+ {
+ }
+ float GetWidth() const override;
+ 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;
+ 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;
+ bool IsCollision(const KRect* other) const;
+ float Width;
+ float Height;
+ };
+}
+
+
diff --git a/2dgk_zad3/2dgk_zad3/KRectPawn.cpp b/2dgk_zad3/2dgk_zad3/KRectPawn.cpp
new file mode 100644
index 0000000..2ef8134
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KRectPawn.cpp
@@ -0,0 +1,15 @@
+#include "KRectPawn.h"
+
+namespace KapitanGame
+{
+ KRectPawn::KRectPawn(const KVector2D& position, const KTexture& texture,
+ const std::shared_ptr& playerController) : KPawn(position, texture, playerController),
+ Collider(this, texture.GetWidth(), texture.GetHeight())
+ {
+ }
+
+ const KCollider* KRectPawn::GetCollider() const
+ {
+ return &Collider;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KRectPawn.h b/2dgk_zad3/2dgk_zad3/KRectPawn.h
new file mode 100644
index 0000000..f2cf0c9
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KRectPawn.h
@@ -0,0 +1,20 @@
+#pragma once
+#include "KPawn.h"
+#include "KRect.h"
+
+namespace KapitanGame
+{
+ class KRectPawn final :
+ public KPawn
+ {
+ public:
+ KRectPawn(const KVector2D& position, const KTexture& texture,
+ const std::shared_ptr& playerController);
+
+ const KCollider* GetCollider() const override;
+ private:
+ KRect Collider;
+ };
+
+
+}
diff --git a/2dgk_zad3/2dgk_zad3/KTexture.cpp b/2dgk_zad3/2dgk_zad3/KTexture.cpp
new file mode 100644
index 0000000..5de09e4
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KTexture.cpp
@@ -0,0 +1,144 @@
+#include "KTexture.h"
+
+namespace KapitanGame {
+ KTexture::KTexture() : Texture(nullptr), Width(0), Height(0)
+ {
+ }
+
+ KTexture::KTexture(KTexture&& other) noexcept
+ : Texture(other.Texture),
+ Width(other.Width),
+ Height(other.Height) {
+ other.Texture = nullptr;
+ other.Width = 0;
+ other.Height = 0;
+ }
+
+ KTexture& KTexture::operator=(KTexture&& other) noexcept {
+ if (this == &other)
+ return *this;
+ Texture = other.Texture;
+ Width = other.Width;
+ Height = other.Height;
+ other.Texture = nullptr;
+ other.Width = 0;
+ other.Height = 0;
+ return *this;
+ }
+
+ KTexture::~KTexture()
+ {
+ //Deallocate
+ Free();
+
+ }
+ bool KTexture::LoadFromFile(const std::string& path, SDL_Renderer* renderer)
+ {
+ //Get rid of preexisting texture
+ Free();
+ //The final texture
+ SDL_Texture* newTexture = nullptr;
+
+ //Load image at specified path
+ SDL_Surface* loadedSurface = SDL_LoadBMP(path.c_str());
+ if (loadedSurface == nullptr)
+ {
+ printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), SDL_GetError());
+ }
+ else
+ {
+ //Color key image
+ SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0xFF, 0, 0));
+ //Create texture from surface pixels
+ newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
+ if (newTexture == nullptr)
+ {
+ printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
+ }
+ else
+ {
+ //Get image dimensions
+ Width = loadedSurface->w;
+ Height = loadedSurface->h;
+ }
+
+ //Get rid of old loaded surface
+ SDL_FreeSurface(loadedSurface);
+ }
+
+ //Return success
+ Texture = newTexture;
+ return Texture != nullptr;
+ }
+
+ bool KTexture::LoadFromSurface(SDL_Surface* surface, SDL_Renderer* renderer)
+ {
+ Free();
+ Texture = SDL_CreateTextureFromSurface(renderer, surface);
+ if (Texture == nullptr)
+ {
+ printf("Unable to create texture from surface! SDL Error: %s\n", SDL_GetError());
+ }
+ else
+ {
+ Width = surface->w;
+ Height = surface->h;
+ }
+ return Texture != nullptr;
+ }
+
+ void KTexture::Free()
+ {
+ //Free texture if it exists
+ if (Texture != nullptr)
+ {
+ SDL_DestroyTexture(Texture);
+ Texture = nullptr;
+ Width = 0;
+ Height = 0;
+ }
+ }
+
+ void KTexture::Render(SDL_Renderer* renderer, const float x, const float y, SDL_Rect* clip, const float scale) const
+ {
+ if (Texture == nullptr) return;
+ //Set rendering space and render to screen
+ SDL_FRect renderQuad = {
+ x * scale, y * scale,
+ Width * scale, Height * scale
+ };
+
+ //Set clip rendering dimensions
+ if (clip != nullptr)
+ {
+ renderQuad.w = clip->w;
+ renderQuad.h = clip->h;
+ }
+
+ //Render to screen
+ SDL_RenderCopyF(renderer, Texture, clip, &renderQuad);
+ }
+
+ void KTexture::RenderEx(SDL_Renderer* renderer, const float x, const float y, const double degrees) const
+ {
+ if (Texture == nullptr) return;
+ //Set rendering space and render to screen
+ const SDL_FRect renderQuad = {
+ x , y ,
+ static_cast(Width) , static_cast(Height)
+ };
+
+ //Render to screen
+ SDL_RenderCopyExF(renderer, Texture, nullptr, &renderQuad, degrees, nullptr, SDL_FLIP_NONE);
+ }
+
+ int KTexture::GetWidth() const
+ {
+ return Width;
+ }
+
+ int KTexture::GetHeight() const
+ {
+ return Height;
+ }
+}
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/KTexture.h b/2dgk_zad3/2dgk_zad3/KTexture.h
new file mode 100644
index 0000000..def9cee
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KTexture.h
@@ -0,0 +1,48 @@
+#pragma once
+#include
+#include
+
+namespace KapitanGame {
+ //Texture wrapper class
+ class KTexture {
+ public:
+ KTexture();
+
+ ~KTexture();
+
+
+ KTexture(const KTexture& other) = delete;
+
+ KTexture(KTexture&& other) noexcept;
+
+ KTexture& operator=(const KTexture& other) = delete;
+
+ KTexture& operator=(KTexture&& other) noexcept;
+
+ //Loads image at specified path
+ bool LoadFromFile(const std::string& path, SDL_Renderer* renderer);
+
+ bool LoadFromSurface(SDL_Surface* surface, SDL_Renderer* renderer);
+
+ //Deallocates texture
+ void Free();
+
+ //Renders texture at given point
+ void Render(SDL_Renderer* renderer, float x, float y, SDL_Rect* clip = nullptr, float scale = 1.f) const;
+
+ void RenderEx(SDL_Renderer* renderer, float x, float y, double degrees) const;
+
+ //Gets image dimensions
+ int GetWidth() const;
+ int GetHeight() const;
+
+ private:
+ //The actual hardware texture
+ SDL_Texture* Texture;
+
+ //Image dimensions
+ int Width;
+ int Height;
+ };
+
+}
diff --git a/2dgk_zad3/2dgk_zad3/KTile.cpp b/2dgk_zad3/2dgk_zad3/KTile.cpp
new file mode 100644
index 0000000..9836c73
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KTile.cpp
@@ -0,0 +1,33 @@
+#include "KTile.h"
+
+#include
+
+#include "Constants.h"
+#include "KTexture.h"
+
+namespace KapitanGame {
+
+ int KTile::GetType() const {
+ return static_cast(Type);
+ }
+
+ SDL_Rect KTile::GetBox() const {
+ return Box;
+ }
+
+ KTile::KTile(const int x, const int y, const TileType tileType) {
+ //Get the offsets
+ Box.x = x;
+ Box.y = y;
+
+ Box.w = Constants::TILE_WIDTH;
+ Box.h = Constants::TILE_HEIGHT;
+
+ //Get the tile type
+ Type = tileType;
+ }
+
+ void KTile::Render(SDL_Renderer* renderer, KTexture tileTextures[], const SDL_Rect& camera, const float scale) const {
+ tileTextures[GetType()].Render(renderer, Box.x - camera.x, Box.y - camera.y, nullptr, scale);
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KTile.h b/2dgk_zad3/2dgk_zad3/KTile.h
new file mode 100644
index 0000000..1c25567
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KTile.h
@@ -0,0 +1,34 @@
+#pragma once
+#include
+#include
+#include
+
+namespace KapitanGame
+{
+ class KTexture;
+
+ enum class TileType : std::uint32_t {
+ Default = 0,
+ Wall = 1
+ };
+ class KTile {
+ public:
+ //Initializes position and type
+ KTile(int x, int y, TileType tileType);
+
+ //Shows the tile
+ void Render(SDL_Renderer* renderer, KTexture tileTextures[], const SDL_Rect& camera, float scale = 1.f) const;
+
+ //Get the tile type
+ int GetType() const;
+
+ SDL_Rect GetBox() const;
+
+ private:
+ //The attributes of the tile
+ SDL_Rect Box{};
+
+ //The tile type
+ TileType Type;
+ };
+}
diff --git a/2dgk_zad3/2dgk_zad3/KVector2d.h b/2dgk_zad3/2dgk_zad3/KVector2d.h
new file mode 100644
index 0000000..5150f64
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KVector2d.h
@@ -0,0 +1,82 @@
+#pragma once
+#include
+#define _USE_MATH_DEFINES
+#include
+
+namespace KapitanGame {
+ struct KVector2D {
+ float X;
+ float Y;
+
+ KVector2D(const float x, const float y) : X(x), Y(y) {}
+
+ float Length() const { return sqrt(X * X + Y * Y); }
+ float Length2() const { return X * X + Y * Y; }
+
+ bool operator==(const KVector2D& v2) const {
+ return (*this - v2).Length2() < FLT_EPSILON * FLT_EPSILON;
+ }
+
+ KVector2D operator+(const KVector2D& v2) const {
+ return { X + v2.X, Y + v2.Y };
+ }
+
+ friend KVector2D& operator+=(KVector2D& v1, const KVector2D& v2) {
+ v1.X += v2.X;
+ v1.Y += v2.Y;
+ return v1;
+ }
+
+ KVector2D operator*(const float scalar) const
+ {
+ return { X * scalar, Y * scalar };
+ }
+
+ KVector2D& operator*=(const float scalar) {
+ X *= scalar;
+ Y *= scalar;
+ return *this;
+ }
+
+ KVector2D operator-(const KVector2D& v2) const {
+ return { X - v2.X, Y - v2.Y };
+ }
+ friend KVector2D& operator-=(KVector2D& v1, const KVector2D& v2) {
+ v1.X -= v2.X;
+ v1.Y -= v2.Y;
+ return v1;
+ }
+
+ KVector2D operator/(const float scalar) const
+ {
+ return { X / scalar, Y / scalar };
+ }
+ KVector2D& operator/=(const float scalar) {
+ X /= scalar;
+ Y /= scalar;
+ return *this;
+ }
+ float DotProduct(const KVector2D& v2) const {
+ return DotProduct(*this, v2);
+ }
+ KVector2D Reflect(const KVector2D& normal) const {
+ return Reflect(normal, *this);
+ }
+
+ void Normalize() {
+ const float l = Length();
+ if (l > 1.f) {
+ (*this) *= 1 / l;
+ }
+ }
+
+ static KVector2D Reflect(const KVector2D& normal, const KVector2D& vector) {
+ const float dn = 2 * vector.DotProduct(normal);
+ return vector - normal * dn;
+ }
+ static float DotProduct(const KVector2D& v1, const KVector2D& v2) {
+ return v1.X * v2.X + v1.Y * v2.Y ;
+ }
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/KWall.cpp b/2dgk_zad3/2dgk_zad3/KWall.cpp
new file mode 100644
index 0000000..d6c3f78
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KWall.cpp
@@ -0,0 +1,9 @@
+#include "KWall.h"
+
+namespace KapitanGame
+{
+ const KCollider* KWall::GetCollider() const
+ {
+ return &Collider;
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/KWall.h b/2dgk_zad3/2dgk_zad3/KWall.h
new file mode 100644
index 0000000..45ca443
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/KWall.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "KObject.h"
+#include "KRect.h"
+
+namespace KapitanGame
+{
+ class KWall final :
+ public KObject
+ {
+ public:
+ KWall(const KVector2D& position, const KTexture& texture)
+ : KObject(position, texture),
+ Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f)
+ {
+ }
+
+ const KCollider* GetCollider() const override;
+ private:
+ KRect Collider;
+ };
+}
+
diff --git a/2dgk_zad3/2dgk_zad3/Main.cpp b/2dgk_zad3/2dgk_zad3/Main.cpp
new file mode 100644
index 0000000..2944d8f
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/Main.cpp
@@ -0,0 +1,8 @@
+#include "KGame.h"
+
+int main(int argc, char* args[])
+{
+ KapitanGame::KGame game;
+
+ return game.Run(argc, args);
+}
diff --git a/2dgk_zad3/2dgk_zad3/Utils.cpp b/2dgk_zad3/2dgk_zad3/Utils.cpp
new file mode 100644
index 0000000..b889ed7
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/Utils.cpp
@@ -0,0 +1,7 @@
+#include "Utils.h"
+
+namespace KapitanGame {
+ namespace Utils {
+
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/Utils.h b/2dgk_zad3/2dgk_zad3/Utils.h
new file mode 100644
index 0000000..e7a9d5e
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/Utils.h
@@ -0,0 +1,109 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+#include "KPlayer.h"
+
+namespace KapitanGame {
+ namespace Utils {
+
+ template
+ std::string StringFormat(const std::string& format, Args ... args)
+ {
+ const int sizeS = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra space for '\0'
+ if (sizeS <= 0) { throw std::runtime_error("Error during formatting."); }
+ const auto size = static_cast(sizeS);
+ const auto buf = std::make_unique(size);
+ std::snprintf(buf.get(), size, format.c_str(), args ...);
+ return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
+ }
+ template
+ constexpr const T& Clamp(const T& x, const T& min, const T& max)
+ {
+ return std::max(std::min(max, x), min);
+ }
+ template
+ constexpr const T& Clamp01(const T& x)
+ {
+ return Clamp(x, 0.f, 1.f);
+ }
+ template
+ constexpr const T& Lerp(const T& a, const T& b, const float& t)
+ {
+ return a + (b - a) * Clamp01(t);
+ }
+
+ static std::default_random_engine make_default_random_engine()
+ {
+ // This gets a source of actual, honest-to-god randomness
+ std::random_device source;
+
+ // Here, we fill an array of random data from the source
+ unsigned int random_data[10];
+ for (auto& elem : random_data) {
+ elem = source();
+ }
+
+ // this creates the random seed sequence out of the random data
+ std::seed_seq seq(random_data + 0, random_data + 10);
+ return std::default_random_engine{ seq };
+ }
+
+ inline std::default_random_engine& GetRandomEngine()
+ {
+ // Making rng static ensures that it stays the same
+ // Between different invocations of the function
+ static std::default_random_engine rng(make_default_random_engine());
+ return rng;
+ }
+
+ inline double RandomNumber() {
+ const std::uniform_real_distribution dist(0.0, 1.0);
+ return dist(GetRandomEngine());
+ }
+
+ template
+ class Iterator {
+ typedef std::underlying_type_t ValT;
+ int Value;
+ public:
+ explicit Iterator(const C& f) : Value(static_cast(f)) {}
+ Iterator() : Value(static_cast(BeginVal)) {}
+ Iterator operator++() {
+ ++Value;
+ return *this;
+ }
+ C operator*() { return static_cast(Value); }
+ Iterator begin() { return *this; } //default ctor is good
+ Iterator end() {
+ static const Iterator END_ITERATE = ++Iterator(EndVal); // cache it
+ return END_ITERATE;
+ }
+ bool operator!=(const Iterator& i) { return Value != i.Value; }
+ };
+
+ inline KPlayer GetPlayerFromString(const std::string& str)
+ {
+ static std::unordered_map const TABLE = { {"Player1",KPlayer::Player1},{"Player2",KPlayer::Player2} };
+ const auto it = TABLE.find(str);
+ if (it != TABLE.end()) {
+ return it->second;
+ }
+ return KPlayer::Player1;
+ }
+
+ typedef Iterator KPlayerIterator;
+
+ struct PairHash {
+ template
+ std::size_t operator () (const std::pair& p) const {
+ auto h1 = std::hash{}(p.first);
+ auto h2 = std::hash{}(p.second);
+ return h1 ^ h2;
+ }
+ };
+ }
+}
diff --git a/2dgk_zad3/2dgk_zad3/assets/fonts/LICENSE.txt b/2dgk_zad3/2dgk_zad3/assets/fonts/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/fonts/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/2dgk_zad3/2dgk_zad3/assets/fonts/OFL.txt b/2dgk_zad3/2dgk_zad3/assets/fonts/OFL.txt
new file mode 100644
index 0000000..c0f4383
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/fonts/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2012 The Press Start 2P Project Authors (cody@zone38.net), with Reserved Font Name "Press Start 2P".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/2dgk_zad3/2dgk_zad3/assets/fonts/PressStart2P-Regular.ttf b/2dgk_zad3/2dgk_zad3/assets/fonts/PressStart2P-Regular.ttf
new file mode 100644
index 0000000..d1b14d4
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/fonts/PressStart2P-Regular.ttf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1732cbf0b83525ca6769c3a58d15de73f38122ed8c056ca7e30a6076767ef3d6
+size 116008
diff --git a/2dgk_zad3/2dgk_zad3/assets/fonts/Roboto-Thin.ttf b/2dgk_zad3/2dgk_zad3/assets/fonts/Roboto-Thin.ttf
new file mode 100644
index 0000000..b7afed0
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/fonts/Roboto-Thin.ttf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bf9760a4821688d544ec7dafba7b060ab1fa758360403537579bf06792d290f8
+size 168488
diff --git a/2dgk_zad3/2dgk_zad3/assets/levels/level1.txt b/2dgk_zad3/2dgk_zad3/assets/levels/level1.txt
new file mode 100644
index 0000000..fee3295
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/levels/level1.txt
@@ -0,0 +1,33 @@
+#################################
+# # # # # # #
+# ######### # # ### # # ### ### #
+# # # # # # # #
+### ### ### ### # ### # # # #####
+# # # # # # # # # # #
+# # ### # # # # ####### # # ### #
+# # # # # # # # # # # #
+####### ### ### # ####### ### # #
+# # # # # # # # # #
+# # # ### ### # # # # ### # #####
+# # # # # # # # # #
+# # ### # ### # # ### # # ### # #
+# # # # # # # # # # #
+# # # ### ### # ### ### ### # # #
+# # # # # # # # # # # #
+# ### ##### ##### # ######### ###
+# # # # # # #
+##### ### # ### ####### # ##### #
+# # # # # #
+# ######### # # ####### ##### ###
+# # # # # # # # #
+### ### ### ########### ### # ###
+# # # # # # #
+# # ### # ### # ##### ### ### # #
+# # # # # # # # #
+# # ##### ### ### ### # ### # ###
+# # # # # # # # # #
+# ##### # # ##### # # ##### #####
+# # # # # # # # # # # # #
+# # ### ##### ####### # # # ### #
+# # # # # #
+#################################
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/assets/levels/level2.txt b/2dgk_zad3/2dgk_zad3/assets/levels/level2.txt
new file mode 100644
index 0000000..9d7cf99
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/levels/level2.txt
@@ -0,0 +1,37 @@
+#####################################
+# # # # # # #
+# ### ### # # # ######### # ##### # #
+# # # # # # # # # #
+### # ### # ####### # # ##### # ### #
+# # # # # # # # #
+### ########### # ### # # # # ### ###
+# # # # # # # # # # # #
+# # ### ### # ### ### # ######### # #
+# # # # # # # # #
+# # ### # # ### # # # ### ######### #
+# # # # # # # # # # # # # #
+# ##### # # # # ####### ### ##### # #
+# # # # # # # #
+# ##### # # # ##### ####### ### # ###
+# # # # # # # # # #
+####### ### ### # # # # ### ####### #
+# # # # # # # # # # # #
+# ##### # # ##### ### # ### # # ### #
+# # # # # # # # # # # # # #
+# # # ### ### ### ### # ### ##### ###
+# # # # # # # # #
+# ####### ##### # ### ####### #######
+# # # # # # #
+# # ### ##### ############# ### #####
+# # # # # # # # # #
+### # # ######### # # # # # # # ### #
+# # # # # # # # # #
+# ##### ### ### # # ### # ### ##### #
+# # # # # # # # # # # #
+# # ### ### # # # # ##### # # # # # #
+# # # # # # # # # # # # # #
+# ####### ### ######### ######### # #
+# # # # # # # # # # #
+# # ######### # # # ##### # # # # # #
+# # # # #
+#####################################
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/assets/levels/level3.txt b/2dgk_zad3/2dgk_zad3/assets/levels/level3.txt
new file mode 100644
index 0000000..96e2dfb
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/levels/level3.txt
@@ -0,0 +1,41 @@
+#########################################
+# # # # # # # #
+# # ### # # ####### ### ####### ####### #
+# # # # # # # # # # #
+# # # # # ##### ####### # ### # ### #####
+# # # # # # # # # #
+# # ### # ##### ##### ### ### # ##### # #
+# # # # # # # # # #
+### ######### ##### ####### ### ##### # #
+# # # # # # # # # # #
+# ### # ### ### ##### # # ### ### # ### #
+# # # # # # # # # # # #
+### ### ####### # # # ####### # # # # # #
+# # # # # # # # # # # # # # #
+# ### # # ### ### # ### # # ### ##### ###
+# # # # # # # # # # # #
+# # # ### ##### ##### # ##### # # ### ###
+# # # # # # # #
+# ####### ### ### # # ######### # #######
+# # # # # # # #
+# ### ##### ### # ########### ######### #
+# # # # # # # # # # # #
+# ##### # # ### ### ### ### # # # # ### #
+# # # # # # # # # # # # #
+# # ### # ### # ### # ##### ##### # # ###
+# # # # # # # # # # # #
+# ##### ####### ####### ### ##### # # # #
+# # # # # # # # # # # # #
+### ### ### ### # # ### ##### ####### # #
+# # # # # # # # #
+### ##### ##### ### ##### # ### ### # # #
+# # # # # # # # # # #
+# ##### # ### ##### # # # ### ### ### # #
+# # # # # # # # # # # #
+##### # ### ##### ### # # # ### # # # ###
+# # # # # # # # # # #
+# ##### ####### ####### # ##### ### # ###
+# # # # # # # # # # #
+# # # # ### ### # ### # ##### ### # # # #
+# # # # # # # # # # # #
+#########################################
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/assets/textures/P1.bmp b/2dgk_zad3/2dgk_zad3/assets/textures/P1.bmp
new file mode 100644
index 0000000..3f1c1f5
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/textures/P1.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4648df597e5ecfa272152784dc7adc867cffed541e1784e8b337022a3438218b
+size 1782
diff --git a/2dgk_zad3/2dgk_zad3/assets/textures/P2.bmp b/2dgk_zad3/2dgk_zad3/assets/textures/P2.bmp
new file mode 100644
index 0000000..335f841
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/textures/P2.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a7c466c5e23dcedc4108ee4d7b64d39dc451f6c91f1f0fff50fb5a62eaf06ece
+size 1782
diff --git a/2dgk_zad3/2dgk_zad3/assets/textures/arrow.bmp b/2dgk_zad3/2dgk_zad3/assets/textures/arrow.bmp
new file mode 100644
index 0000000..ee330c7
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/textures/arrow.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9216fa8cd3c863a9ff910c86d4d7b7cf03fe2f8164cfccf41eaa80f5779d3721
+size 3126
diff --git a/2dgk_zad3/2dgk_zad3/assets/textures/exit.bmp b/2dgk_zad3/2dgk_zad3/assets/textures/exit.bmp
new file mode 100644
index 0000000..45b5912
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/textures/exit.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e75171d7751468d4c0042916a2650f82cb3c4989973452805d3e73cd3843a44f
+size 3126
diff --git a/2dgk_zad3/2dgk_zad3/assets/textures/wall.bmp b/2dgk_zad3/2dgk_zad3/assets/textures/wall.bmp
new file mode 100644
index 0000000..dc1e5eb
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/assets/textures/wall.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0fce8eb3cb3ca774fe68a04a8f16f28c889d9e0809ca21a0b1d39edbc796d786
+size 3126
diff --git a/2dgk_zad3/2dgk_zad3/config.json b/2dgk_zad3/2dgk_zad3/config.json
new file mode 100644
index 0000000..c9a79fb
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/config.json
@@ -0,0 +1,33 @@
+{
+ "Input": {
+ "Player1": {
+ "AxisMappings": [
+ {
+ "AxisName": "MoveX",
+ "Scale": 1.000000,
+ "Key": "D"
+ },
+ {
+ "AxisName": "MoveX",
+ "Scale": -1.000000,
+ "Key": "A"
+ },
+ {
+ "AxisName": "MoveX",
+ "Scale": 1.000000,
+ "Key": "Gamepad0_LeftX"
+ }
+ ],
+ "ActionMappings": [
+ {
+ "ActionName": "Jump",
+ "Key": "Space"
+ },
+ {
+ "ActionName": "Jump",
+ "Key": "Gamepad0_A"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/2dgk_zad3/2dgk_zad3/resource.h b/2dgk_zad3/2dgk_zad3/resource.h
new file mode 100644
index 0000000..d4f4885
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by 2dgk_zad3.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/2dgk_zad3/2dgk_zad3/vcpkg.json b/2dgk_zad3/2dgk_zad3/vcpkg.json
new file mode 100644
index 0000000..e424a6f
--- /dev/null
+++ b/2dgk_zad3/2dgk_zad3/vcpkg.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
+ "name": "dgk-zad3",
+ "version": "0.1.0",
+ "dependencies": [
+ "sdl2",
+ "nlohmann-json",
+ "sdl2-ttf"
+ ]
+}
\ No newline at end of file
diff --git a/2dgk_zad3/readme.txt b/2dgk_zad3/readme.txt
new file mode 100644
index 0000000..2bceeec
--- /dev/null
+++ b/2dgk_zad3/readme.txt
@@ -0,0 +1,7 @@
+IDE: Microsoft Visual Studio 2022
+Kompilator: Microsoft Visual C++
+Biblioteki: SDL2, SDL2_ttf, nlohmann-json
+
+Przetestowane pady: DualSense, DualShock 3 (ze sterownikiem/wrapperem XInputowym ScpToolkit), telefon Android (ze sterownikiem/wrapperem XInputowym HandyGamePad).
+
+Uwaga: Do pobrania bibliotek projekt wykorzystuje vcpkg, menedżer bibliotek C++, w trybie Manifest. Należy go pobrać i skonfigurować zgodnie z instrukcją: https://github.com/microsoft/vcpkg#getting-started