This commit is contained in:
Michał Leśniak 2022-01-20 08:52:14 +01:00
parent 7623bde891
commit 0a34c2e094
70 changed files with 3766 additions and 0 deletions

1
.gitattributes vendored
View File

@ -1,2 +1,3 @@
*.bmp filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text

View File

@ -4,4 +4,13 @@ Biblioteki: SDL2, SDL2_ttf, nlohmann-json
Przetestowane pady: DualSense, DualShock 3 (ze sterownikiem/wrapperem XInputowym ScpToolkit), telefon Android (ze sterownikiem/wrapperem XInputowym HandyGamePad).
Sterowanie (możliwa zmiana w config.json):
AD/lewa gałka pada - ruch poziomy
Spacja/A na padzie - skok
F1 - tryb deweloperski
F2 (w trybie deweloperskim) - wł./wył. kolizji
F3/F4 - (w trybie deweloperskim) - zwiększ/zmiejsz maksymalną wysokość skoku.
F5/F6 - (w trybie deweloperskim) - zwiększ/zmiejsz maksymalną odległość poziomą skoku
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

31
2dkg_zad5/2dgk_zad5.sln Normal file
View File

@ -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_zad5", "2dgk_zad5\2dgk_zad5.vcxproj", "{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}"
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
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Debug|x64.ActiveCfg = Debug|x64
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Debug|x64.Build.0 = Debug|x64
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Debug|x86.ActiveCfg = Debug|Win32
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Debug|x86.Build.0 = Debug|Win32
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Release|x64.ActiveCfg = Release|x64
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Release|x64.Build.0 = Release|x64
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Release|x86.ActiveCfg = Release|Win32
{2696A0B3-E7C4-4876-9DF4-E7D3EC6C06F8}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2292BE73-514E-4923-9A1A-5A991B0DE0DB}
EndGlobalSection
EndGlobal

View File

@ -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_zad5.exe"
VALUE "LegalCopyright", "Copyright (C) 2022 Michał Leśniak"
VALUE "OriginalFilename", "2dgk_zad5.exe"
VALUE "ProductName", "2DKG_ZAD5"
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

View File

@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2696a0b3-e7c4-4876-9df4-e7d3ec6c06f8}</ProjectGuid>
<RootNamespace>My2dgk_zad5</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>true</VcpkgEnableManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>vcpkg_installed\x86-windows\x86-windows\include\SDL2</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>vcpkg_installed\x86-windows\x86-windows\debug\lib\manual-link;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2maind.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>vcpkg_installed\x86-windows\x86-windows\include\SDL2</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>vcpkg_installed\x86-windows\x86-windows\lib\manual-link;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>vcpkg_installed\x64-windows\x64-windows\include\SDL2</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>vcpkg_installed\x64-windows\x64-windows\debug\lib\manual-link;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2maind.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>vcpkg_installed\x64-windows\x64-windows\include\SDL2</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>vcpkg_installed\x64-windows\x64-windows\lib\manual-link;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="KCamera.cpp" />
<ClCompile Include="KCircle.cpp" />
<ClCompile Include="KCirclePawn.cpp" />
<ClCompile Include="KDrawable.cpp" />
<ClCompile Include="KFont.cpp" />
<ClCompile Include="KGame.cpp" />
<ClCompile Include="KInput.cpp" />
<ClCompile Include="KSolid.cpp" />
<ClCompile Include="KPawn.cpp" />
<ClCompile Include="KPlayerController.cpp" />
<ClCompile Include="KRect.cpp" />
<ClCompile Include="KCollider.cpp" />
<ClCompile Include="KRectPawn.cpp" />
<ClCompile Include="KSettings.cpp" />
<ClCompile Include="KTexture.cpp" />
<ClCompile Include="KSolidTile.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="config.json">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="vcpkg.json" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Constants.h" />
<ClInclude Include="Controllers.h" />
<ClInclude Include="GamePad.h" />
<ClInclude Include="KActionBind.h" />
<ClInclude Include="KCamera.h" />
<ClInclude Include="KCircle.h" />
<ClInclude Include="KCirclePawn.h" />
<ClInclude Include="KDrawable.h" />
<ClInclude Include="KFont.h" />
<ClInclude Include="KGame.h" />
<ClInclude Include="KInput.h" />
<ClInclude Include="KSolid.h" />
<ClInclude Include="KPawn.h" />
<ClInclude Include="KPlayer.h" />
<ClInclude Include="KPlayerController.h" />
<ClInclude Include="KRect.h" />
<ClInclude Include="KCollider.h" />
<ClInclude Include="KRectPawn.h" />
<ClInclude Include="KSettings.h" />
<ClInclude Include="KTexture.h" />
<ClInclude Include="KSolidTile.h" />
<ClInclude Include="Property.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="KVector2d.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2dgk_zad5.rc" />
</ItemGroup>
<ItemGroup>
<Text Include="assets\fonts\LICENSE.txt">
<DeploymentContent>true</DeploymentContent>
</Text>
<Text Include="assets\levels\level1.txt">
<DeploymentContent>true</DeploymentContent>
</Text>
</ItemGroup>
<ItemGroup>
<Font Include="assets\fonts\Roboto-Thin.ttf">
<DeploymentContent>true</DeploymentContent>
</Font>
</ItemGroup>
<ItemGroup>
<Image Include="assets\textures\arrow.bmp">
<DeploymentContent>true</DeploymentContent>
</Image>
<Image Include="assets\textures\exit.bmp">
<DeploymentContent>true</DeploymentContent>
</Image>
<Image Include="assets\textures\P1.bmp">
<DeploymentContent>true</DeploymentContent>
</Image>
<Image Include="assets\textures\P2.bmp">
<DeploymentContent>true</DeploymentContent>
</Image>
<Image Include="assets\textures\wall.bmp">
<DeploymentContent>true</DeploymentContent>
</Image>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties />
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KTexture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KGame.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KInput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KCircle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KPlayerController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KCollider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KRect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KSolid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KPawn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KSolidTile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KRectPawn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KCirclePawn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KCamera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KFont.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KSettings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KDrawable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="vcpkg.json" />
<None Include="config.json" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Constants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KVector2d.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KTexture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KGame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GamePad.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KInput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KCircle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KPlayerController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KCollider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KRect.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KActionBind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Controllers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KPlayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KSolid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KPawn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KSolidTile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KRectPawn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KCirclePawn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KCamera.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KFont.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KSettings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Property.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KDrawable.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2dgk_zad5.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="assets\textures\arrow.bmp">
<Filter>Resource Files</Filter>
</Image>
<Image Include="assets\textures\exit.bmp">
<Filter>Resource Files</Filter>
</Image>
<Image Include="assets\textures\P1.bmp">
<Filter>Resource Files</Filter>
</Image>
<Image Include="assets\textures\P2.bmp">
<Filter>Resource Files</Filter>
</Image>
<Image Include="assets\textures\wall.bmp">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Font Include="assets\fonts\Roboto-Thin.ttf" />
</ItemGroup>
<ItemGroup>
<Text Include="assets\fonts\LICENSE.txt" />
<Text Include="assets\levels\level1.txt" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
#pragma once
namespace KapitanGame::Constants
{
constexpr const char* WINDOW_TITLE = "2DGK - Zadanie 5 (Lab 14)";
//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<float>(SCREEN_WIDTH) / SCREEN_HEIGHT;
constexpr int TILE_WIDTH = 32;
constexpr int TILE_HEIGHT = 32;
constexpr int TILE_COUNT = 8;
constexpr int BG_LAYER_COUNT = 3;
constexpr int FG_LAYER_COUNT = 1;
constexpr float SPEED = 200.f;
constexpr float SMOOTH = 0.4f;
constexpr float JUMP_SPEED = 300.f;
constexpr float HORIZONTAL_DISTANCE_TO_MAX_JUMP_HEIGHT = TILE_WIDTH * 4.f;
constexpr float MAX_JUMP_HEIGHT = TILE_HEIGHT * 4.f;
constexpr float MAX_GRAVITY = 1000.f;
}

View File

@ -0,0 +1,9 @@
#pragma once
namespace KapitanGame {
enum class Controllers : int {
Controller1,
Controller2,
Controller3,
Controller4
};
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <SDL_gamecontroller.h>
namespace KapitanGame {
struct GamePad {
bool Buttons[SDL_CONTROLLER_BUTTON_MAX];
int Axis[SDL_CONTROLLER_AXIS_MAX];
};
}

View File

@ -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<KPlayerController>& 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<KPlayerController> ControllerObject;
KPlayerCommand Command;
KPlayer Player;
};
struct KAxisBind
{
KAxisBind(std::string name, const std::shared_ptr<KPlayerController>& controllerObject, const KPlayerAxisCommand command, const KPlayer player) :
Name(std::move(name)), ControllerObject(controllerObject), AxisCommand(command), Player(player) {}
std::string Name;
std::weak_ptr<KPlayerController> ControllerObject;
KPlayerAxisCommand AxisCommand;
KPlayer Player;
};
}

View File

@ -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<std::shared_ptr<KPawn>>& pawns, const SDL_FRect& map)
{
FocusPoint = { 0.f,0.f };
for(const auto& pawn : pawns) {
FocusPoint += pawn->GetPosition();
}
FocusPoint *= 1.f / static_cast<float>(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<float>(-Constants::WINDOW_DEAD_ZONE), map.w + static_cast<float>(Constants::WINDOW_DEAD_ZONE));
PlayArea.y = Utils::Clamp(FocusPoint.Y - PlayArea.h / 2.f, static_cast<float>(-Constants::WINDOW_DEAD_ZONE), map.h + static_cast<float>(Constants::WINDOW_DEAD_ZONE));
}
void KCamera::SetDebug(const SDL_FRect& map)
{
Viewport = { 0,0,Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT };
Scale = std::min(Constants::SCREEN_HEIGHT * 1.f / map.h, Constants::SCREEN_WIDTH * 1.f / map.w);
}
const SDL_FRect& KCamera::GetPlayArea() const
{
return PlayArea;
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <memory>
#include <SDL_rect.h>
#include <vector>
#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<std::shared_ptr<KPawn>>& 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;
};
}

View File

@ -0,0 +1,108 @@
#include "KCircle.h"
#include <SDL_rect.h>
#include <stdexcept>
#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
{
if (const auto circle = dynamic_cast<const KCircle*>(other); circle != nullptr)
return IsCollision(circle);
if (const auto rect = dynamic_cast<const KRect*>(other); rect != nullptr)
return IsCollision(rect);
throw std::runtime_error("unsupported shape");
}
KVector2D KCircle::GetSeparationVector(const KCollider* other) const
{
if (const auto circle = dynamic_cast<const KCircle*>(other); circle != nullptr)
return GetSeparationVector(circle);
if (const auto rect = dynamic_cast<const KRect*>(other); 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(KSolid* parent, const float radius): KCollider(parent),
Radius(radius)
{
}
float KCircle::GetRadius() const {
return Radius;
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <SDL_rect.h>
#include "KCollider.h"
#include "KVector2d.h"
namespace KapitanGame {
class KRect;
class KCircle final : public KCollider
{
public:
KCircle(KSolid* parent, float radius);
[[nodiscard]] 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;
[[nodiscard]] KVector2D GetSeparationVector(const SDL_FRect& map) const override;
[[nodiscard]] float GetWidth() const override;
[[nodiscard]] float GetHeight() const override;
private:
float Radius{ 1.f };
};
}

View File

@ -0,0 +1,15 @@
#include "KCirclePawn.h"
namespace KapitanGame
{
KCirclePawn::KCirclePawn(const KVector2D& position, const KTexture& texture,
const std::shared_ptr<KPlayerController>& playerController, KSettings* settings) : KPawn(position, texture, playerController, settings),
Collider(this, static_cast<float>(texture.GetWidth())/2.0f)
{
}
const KCollider* KCirclePawn::GetCollider() const
{
return &Collider;
}
}

View File

@ -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<KPlayerController>& playerController, KSettings* settings);
const KCollider* GetCollider() const override;
private:
KCircle Collider;
};
}

View File

@ -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(KSolid* parent): Parent(parent)
{
}
KSolid* KCollider::GetParent() const
{
return Parent;
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <SDL_rect.h>
#include "KSolid.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(KSolid* parent);
virtual ~KCollider() = default;
virtual bool IsCollision(const KCollider* other) const = 0;
virtual KVector2D GetSeparationVector(const KCollider* other) const = 0;
[[nodiscard]] virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0;
[[nodiscard]] virtual float GetWidth() const = 0;
[[nodiscard]] virtual float GetHeight() const = 0;
[[nodiscard]] KSolid* GetParent() const;
private:
KSolid* Parent;
};
}

View File

@ -0,0 +1,26 @@
#include "KDrawable.h"
#include "KCamera.h"
namespace KapitanGame
{
std::atomic<int> KDrawable::IdCounter{ 0 };
KDrawable::KDrawable(const KVector2D& position, const KTexture& texture, SDL_Rect* tileClip, const SDL_RendererFlip flip) :
Id(++IdCounter), Position(position), Texture(texture), TileClip(tileClip), Flip(flip)
{
}
void KDrawable::Render(SDL_Renderer* renderer, const KCamera& camera, const float parallaxFactor) const
{
if (TileClip != nullptr)
Texture.RenderEx(renderer, Position.X - Constants::TILE_WIDTH / 2.f - camera.GetViewport().x * parallaxFactor, Position.Y - Constants::TILE_HEIGHT / 2.f - camera.GetViewport().y, 0, TileClip, camera.GetScale(), Flip); // NOLINT(clang-diagnostic-implicit-int-float-conversion, bugprone-narrowing-conversions, cppcoreguidelines-narrowing-conversions)
else
Texture.Render(renderer, Position.X - Texture.GetWidth() / 2.f - camera.GetViewport().x * parallaxFactor, Position.Y - Texture.GetHeight() / 2.f - camera.GetViewport().y, nullptr, camera.GetScale()); // NOLINT(clang-diagnostic-implicit-int-float-conversion, bugprone-narrowing-conversions, cppcoreguidelines-narrowing-conversions)
}
KVector2D KDrawable::GetPosition() const
{
return Position;
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <atomic>
#include "KTexture.h"
#include "KVector2d.h"
namespace KapitanGame
{
class KCamera;
class KDrawable
{
public:
KDrawable(const KVector2D& position, const KTexture& texture, SDL_Rect* tileClip, SDL_RendererFlip flip = SDL_FLIP_NONE);
virtual ~KDrawable() = default;
void Render(SDL_Renderer* renderer, const KCamera& camera, float parallaxFactor = 1.f) const;
[[nodiscard]] KVector2D GetPosition() const;
const int Id;
static std::atomic<int> IdCounter;
protected:
KVector2D Position{ 0.f, 0.f };
private:
const KTexture& Texture;
SDL_Rect* TileClip;
const SDL_RendererFlip Flip;
};
}

View File

@ -0,0 +1,132 @@
#include "KFont.h"
#include <sstream>
#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;
constexpr int spacing = 1;
int width, height = width = 0;
std::istringstream inputText;
inputText.str(text);
for(std::string line; std::getline(inputText, line);)
{
int w, h;
TTF_SizeText(Font, line.c_str(), &w, &h);
if (w > width) width = w;
height += w+spacing;
}
if (height > 0)
height -= spacing;
inputText.clear();
inputText.seekg(0);
SDL_Surface* textureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 8, SDL_PIXELFORMAT_INDEX8);
{
const SDL_Palette* palette = textureSurface->format->palette;
palette->colors[0].r = 255 - textColor.r;
palette->colors[0].g = 255 - textColor.g;
palette->colors[0].b = 255 - textColor.b;
palette->colors[1].r = textColor.r;
palette->colors[1].g = textColor.g;
palette->colors[1].b = textColor.b;
palette->colors[1].a = textColor.a;
}
SDL_SetColorKey(textureSurface, SDL_TRUE, 0);
int y = 0;
for (std::string line; std::getline(inputText, line);) {
if (SDL_Surface* textSurface = TTF_RenderText_Solid(Font, line.c_str(), textColor); textSurface == nullptr)
{
printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
}
else
{
SDL_Rect destRect{0, y, textSurface->w, textSurface->h};
SDL_BlitSurface(textSurface, nullptr, textureSurface, &destRect);
y += textSurface->h + spacing;
SDL_FreeSurface(textSurface);
}
}
texture.LoadFromSurface(textureSurface, renderer);
SDL_FreeSurface(textureSurface);
return texture;
}
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;
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <SDL_ttf.h>
#include <string>
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{};
};
}

View File

@ -0,0 +1,473 @@
#include "KGame.h"
#include "SDL.h"
#include <SDL_ttf.h>
#include <SDL_image.h>
#include <nlohmann/json.hpp>
#include <cstdio>
#include <string>
#include <fstream>
#include <vector>
#include "Utils.h"
#include "Constants.h"
#include "KCamera.h"
#include "KCirclePawn.h"
#include "KTexture.h"
#include "KTile.h"
#include "KVector2d.h"
#include "KSolidTile.h"
namespace KapitanGame {
KGame::KGame() : Time(0), PreviousTime(0), Map(), Settings(Constants::MAX_JUMP_HEIGHT, Constants::HORIZONTAL_DISTANCE_TO_MAX_JUMP_HEIGHT)
{
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
throw std::runtime_error(Utils::StringFormat("SDL could not initialize! SDL_Error: %s", SDL_GetError()));
}
#ifndef NDEBUG
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
#endif
////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()));
}
if (IMG_Init(IMG_INIT_PNG) < 0)
{
throw std::runtime_error(Utils::StringFormat("SDL_IMG could not initialize! IMG_Error: %s", IMG_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);
SDL_Log("KGame initialized...");
}
KGame::~KGame() {
//Free loaded images
Textures.clear();
for (auto& layer : BackgroundLayers)
{
layer.clear();
}
Objects.clear();
for (auto& layer : ForegroundLayers)
{
layer.clear();
}
Pawns.clear();
PlayerControllers.clear();
Fonts.clear();
TTF_Quit();
IMG_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();
Pawns.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;
int layer = 0;
float mapWidth = 0, mapHeight = 0;
KVector2D startPosition{ 0.f, 0.f };
std::string line;
while (std::getline(levelFile, line)) {
if (line.length() > 0 && line[0] == '#')
{
std::string mapSizes = line.substr(1);
const auto delimPos = mapSizes.find(',');
mapWidth = std::stof(mapSizes.substr(0, delimPos)) * Constants::TILE_WIDTH;
mapHeight = std::stof(mapSizes.substr(delimPos + 1)) * Constants::TILE_HEIGHT;
continue;
}
if (line.length() > 0 && line[0] == '!')
{
layer = std::stoi(line.substr(1));
y = 0;
continue;
}
for (auto i = 0ull; i < line.length(); ++i) {
KVector2D position{
static_cast<float>(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2), // NOLINT(bugprone-integer-division)
static_cast<float>(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) // NOLINT(bugprone-integer-division)
};
if (layer == 3) {
switch (line[i])
{
case 'P':
startPosition = position;
break;
default:
auto clip = -1;
SDL_RendererFlip flip = SDL_FLIP_NONE;
if (std::isdigit(line[i]))
{
clip = line[i] - '0';
}
else if (line[i] >= 'a' && line[i] <= 'z')
{
clip = line[i] - 'a';
flip = SDL_FLIP_HORIZONTAL;
}
if (clip >= 0)
Objects.emplace(std::make_pair(static_cast<int>(i), y), std::make_shared<KSolidTile>(position, Textures["tiles"], &TileClips[clip], flip));
break;
}
}
else if (layer < 3)
{
auto clip = -1;
SDL_RendererFlip flip = SDL_FLIP_NONE;
if (std::isdigit(line[i]))
{
clip = line[i] - '0';
}
else if (line[i] >= 'a' && line[i] <= 'z')
{
clip = line[i] - 'a';
flip = SDL_FLIP_HORIZONTAL;
}
if (clip >= 0)
BackgroundLayers[layer].emplace(std::make_pair(static_cast<int>(i), y), std::make_shared<KDrawable>(position, Textures["tiles"], &TileClips[clip], flip));
}
else
{
const auto index = layer - 4;
auto clip = -1;
SDL_RendererFlip flip = SDL_FLIP_NONE;
if (std::isdigit(line[i]))
{
clip = line[i] - '0';
}
else if (line[i] >= 'a' && line[i] <= 'z')
{
clip = line[i] - 'a';
flip = SDL_FLIP_HORIZONTAL;
}
if (clip >= 0)
ForegroundLayers[index].emplace(std::make_pair(static_cast<int>(i), y), std::make_shared<KDrawable>(position, Textures["tiles"], &TileClips[clip], flip));
}
}
++y;
}
levelFile.close();
Map = { 0,0,mapWidth,mapHeight };
Pawns.emplace_back(std::make_shared<KCirclePawn>(startPosition, Textures["P1.bmp"], PlayerControllers[static_cast<int>(KPlayer::Player1)], &Settings));
PlayerControllers[static_cast<int>(KPlayer::Player1)]->Possess(Pawns.back().get());
}
return success;
}
bool KGame::LoadMedia()
{
//Loading success flag
bool success = true;
for (auto player : Utils::KPlayerIterator())
{
std::string filename = "P" + std::to_string(static_cast<int>(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<KPlayerController>(player));
PlayerControllers.back()->SetupInputBindings(Input);
}
Textures.emplace("tiles", KTexture());
if (!Textures["tiles"].LoadFromFile("assets/textures/maptiles.png", Renderer))
{
printf("Failed to load map tiles texture image!\n");
Textures.erase("tiles");
success = false;
}
else
{
for (int i = 0; i < Constants::TILE_COUNT; ++i)
{
TileClips[i].x = (i % 4) * Constants::TILE_WIDTH;
TileClips[i].y = (i / 4) * Constants::TILE_HEIGHT;
TileClips[i].w = Constants::TILE_WIDTH;
TileClips[i].h = Constants::TILE_HEIGHT;
}
}
Fonts.emplace("PressStart2P-Regular", KFont());
if (!Fonts["PressStart2P-Regular"].LoadFromFile("assets/fonts/PressStart2P-Regular.ttf", 8))
{
printf("Failed to load PressStart2P-Regular font!\n");
Fonts.erase("PressStart2P-Regular");
success = false;
}
if (std::ifstream configFile("config.json"); 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<std::string>(), axisMapping["Scale"].get<float>(), axisMapping["Key"].get<std::string>(), playerEnum);
}
for (auto& actionMapping : player.value()["ActionMappings"]) {
Input.AddActionMapping(actionMapping["ActionName"].get<std::string>(), actionMapping["Key"].get<std::string>(), 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);
char devMode = 0;
camera.Update(Pawns, Map);
SettingsTextTextureDirty = true;
Time = PreviousTime = SDL_GetTicks();
printf("\n");
//While application is running
while (!quit)
{
PreviousTime = Time;
Time = SDL_GetTicks();
float deltaTime = static_cast<float>(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))
{
if (++devMode > 2) devMode = 0;
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Changed devMode to %d\n", devMode);
}
if (devMode >= 1) {
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2))
{
Settings.CollisionEnabled = !Settings.CollisionEnabled;
}
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F3))
{
Settings.MaxJumpHeight -= 0.1f;
SettingsTextTextureDirty = true;
}
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F4))
{
Settings.MaxJumpHeight += 0.1f;
SettingsTextTextureDirty = true;
}
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F5))
{
Settings.HorizontalDistanceToMaxJumpHeight -= 0.1f;
SettingsTextTextureDirty = true;
}
if (Input.IsKeyboardButtonHeld(SDL_SCANCODE_F6))
{
Settings.HorizontalDistanceToMaxJumpHeight += 0.1f;
SettingsTextTextureDirty = true;
}
}
if (Playing) {
for (const auto& pc : PlayerControllers) {
pc->Update(deltaTime);
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->MovementStep(deltaTime);
}
if (Settings.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);
}
Textures.insert_or_assign("Text_Settings", Fonts["PressStart2P-Regular"].GetTextTexture(
Utils::StringFormat(
"Developer Mode (F1): %d\n"
"Collision Enabled (F2): %s\n"
"Max Jump Height (F3/F4): %f\n"
"Horizontal Distance to Max Jump Height (F5/F6): %f\n"
"Initial Jump Velocity: %f\n"
"Gravity: %f\n"
"Player Position X: %f\n"
"Player Position Y: %f",
static_cast<int>(devMode),
Settings.CollisionEnabled ? "True" : "False",
static_cast<float>(Settings.MaxJumpHeight),
static_cast<float>(Settings.HorizontalDistanceToMaxJumpHeight),
static_cast<float>(Settings.JumpInitialVelocity),
static_cast<float>(Settings.Gravity),
Pawns.back()->GetPosition().X,
Pawns.back()->GetPosition().Y), { 0, 0, 0, 0xFF },
Renderer));
if (!Playing)
{
if (Time > RestartTick)
{
LoadLevel();
debugCamera.SetDebug(Map);
camera.Update(Pawns, Map);
Playing = true;
continue;
}
}
//Clear screen
//SDL_SetRenderDrawColor(Renderer, 66, 135, 245, 0xFF);
SDL_SetRenderDrawColor(Renderer, 21, 36, 143, 0xFF);
SDL_RenderClear(Renderer);
const auto& cameraInUse = devMode >= 2 ? debugCamera : camera;
if (Playing) {
for (int i = 0; i < Constants::BG_LAYER_COUNT; ++i)
{
for (const auto& [tile, drawable] : BackgroundLayers[i])
drawable->Render(Renderer, cameraInUse, 1.f - (Constants::BG_LAYER_COUNT - i - 1) * .25f); //TODO: Add controls for changing parallax factor
}
for (const auto& [tile, obj] : Objects)
obj->Render(Renderer, cameraInUse);
for (const auto& pawn : Pawns) {
pawn->Render(Renderer, cameraInUse);
}
for (auto& layer : ForegroundLayers)
{
for (const auto& [tile, drawable] : layer)
drawable->Render(Renderer, cameraInUse);
}
}
if (devMode >= 1) {
Textures["Text_Settings"].Render(Renderer, 10.f, 25.f);
}
if (devMode >= 2)
{
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;
}
}

View File

@ -0,0 +1,59 @@
#pragma once
#include <memory>
#include "KTexture.h"
#include <vector>
#include <SDL_render.h>
#include "Constants.h"
#include "KFont.h"
#include "KInput.h"
#include "KSettings.h"
#include "Utils.h"
namespace KapitanGame {
class KExit;
class KSolid;
class KGame
{
public:
KGame();
~KGame();
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::pair<int, int>, std::shared_ptr<KDrawable>, Utils::PairHash> BackgroundLayers[Constants::BG_LAYER_COUNT];
std::unordered_map<std::pair<int, int>, std::shared_ptr<KDrawable>, Utils::PairHash> ForegroundLayers[Constants::FG_LAYER_COUNT];
std::unordered_map<std::pair<int, int>, std::shared_ptr<KSolid>, Utils::PairHash> Objects;
std::vector<std::shared_ptr<KPawn>> Pawns;
std::vector<std::shared_ptr<KPlayerController>> PlayerControllers;
std::unordered_map<std::string, KTexture> Textures;
std::unordered_map<std::string, KFont> Fonts;
SDL_Rect TileClips[Constants::TILE_COUNT];
KInput Input;
uint32_t Time;
uint32_t PreviousTime;
SDL_FRect Map;
std::weak_ptr<KSolid> Exit;
KSettings Settings;
bool SettingsTextTextureDirty = true;
bool LoadLevel();
bool LoadMedia();
int LvlCounter = 1;
bool Playing = true;
uint32_t RestartTick = -1;
};
}

View File

@ -0,0 +1,307 @@
#include "KInput.h"
#include "Constants.h"
#include <SDL.h>
#include <algorithm>
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<Uint8>(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;
default: break;
}
}
void KInput::BindAction(const std::string& name, InputState expectedInputState,
const std::shared_ptr<KPlayerController>& controllerObject,
KPlayerCommand command, KPlayer player) {
Actions.emplace_back(name, expectedInputState, controllerObject, command, player);
}
void KInput::BindAxis(const std::string& name, const std::shared_ptr<KPlayerController>& 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<int>(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<int>(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<Controllers>(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<int>(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<int>(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<Controllers>(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<int>(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<int>(player)].emplace(name, scanCode);
}
}
}
bool KInput::IsControllerButtonPressed(const Controllers controllerId, const SDL_GameControllerButton button) const
{
if (controllerId < Controllers::Controller1 || controllerId > static_cast<Controllers>(GamePadsCount - 1)) return false;
return ControllerInputs[static_cast<int>(controllerId)].Buttons[button] && !LastControllerInputs[static_cast<int>(controllerId)].Buttons[button];
}
bool KInput::IsControllerButtonReleased(const Controllers controllerId, const SDL_GameControllerButton button) const
{
if (controllerId < Controllers::Controller1 || controllerId > static_cast<Controllers>(GamePadsCount - 1)) return false;
return !ControllerInputs[static_cast<int>(controllerId)].Buttons[button] && LastControllerInputs[static_cast<int>(controllerId)].Buttons[button];
}
bool KInput::IsControllerButtonHeld(const Controllers controllerId, const SDL_GameControllerButton button) const
{
if (controllerId < Controllers::Controller1 || controllerId > static_cast<Controllers>(GamePadsCount - 1)) return false;
return ControllerInputs[static_cast<int>(controllerId)].Buttons[button] && LastControllerInputs[static_cast<int>(controllerId)].Buttons[button];
}
float KInput::GetControllerAxis(const Controllers controllerId, const SDL_GameControllerAxis axis) const
{
if (controllerId <Controllers::Controller1 || controllerId > static_cast<Controllers>(GamePadsCount - 1)) return 0.0;
const int value = ControllerInputs[static_cast<int>(controllerId)].Axis[axis];
if (std::abs(value) < Constants::JOYSTICK_DEAD_ZONE) return 0.0;
return static_cast<float>(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<int>(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<int>(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];
}
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <SDL_events.h>
#include <unordered_map>
#include <vector>
#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<SDL_GameController*> ConnectedControllers;
std::vector<GamePad> ControllerInputs;
std::vector<GamePad> LastControllerInputs;
std::vector<Uint8> KeyboardInputs;
std::vector<Uint8> LastKeyboardInputs;
std::vector<KActionBind> Actions;
std::vector<KAxisBind> Axes;
std::unordered_multimap<std::string, Uint8> KeyBinds[static_cast<int>(KPlayer::Player2) + 1];
std::unordered_multimap<std::string, std::pair<Controllers, SDL_GameControllerButton>> ButtonBinds[static_cast<int>(KPlayer::Player2) + 1];
std::unordered_multimap<std::string, KControllerAxisMapping> ControllerAxisBinds[static_cast<int>(KPlayer::Player2) + 1];
std::unordered_multimap<std::string, std::pair<Uint8, float>> KeyAxisBinds[static_cast<int>(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<KPlayerController>& controllerObject, KPlayerCommand command, KPlayer player);
void BindAxis(const std::string& name, const std::shared_ptr<KPlayerController>& 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;
};
}

View File

@ -0,0 +1,106 @@
#include "KPawn.h"
#include <memory>
//#include <typeinfo>
#include "Constants.h"
#include "KCollider.h"
//#include "KPlayerController.h"
#include "KSettings.h"
namespace KapitanGame
{
void KPawn::CollisionDetectionStep(const std::unordered_map<std::pair<int, int>, std::shared_ptr<KSolid>, Utils::PairHash>& objects)
{
if (GetCollider() == nullptr) return;
const auto xPos = static_cast<int>(GetPosition().X / Constants::TILE_WIDTH);
const auto yPos = static_cast<int>(GetPosition().Y / Constants::TILE_HEIGHT);
for (const auto& [oX, oY] : std::initializer_list<std::pair<int, int>>{ {0, 0}, {-1,0}, {1,0}, {0,-1}, {0,1}, {-1,-1}, {1,1}, {1,-1}, {-1,1} })
{
auto it = objects.find({ xPos + oX, yPos + oY });
if (it == objects.end()) continue;
const auto& other = it->second;
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 (GetPosition().Y - GetCollider()->GetHeight() / 2.f >= other->GetPosition().Y + other->GetCollider()->GetHeight() / 2.f)
{
Velocity.Y = 0;
}
if (GetPosition().Y + GetCollider()->GetHeight() / 2.f <= other->GetPosition().Y - other->GetCollider()->GetHeight() / 2.f)
{
Velocity.Y = 0;
CanJump = true;
CanDoubleJump = true;
HasJumped = false;
}
}
}
}
void KPawn::MovementStep(const float& timeStep)
{
const float gravityScale = Velocity.Y > 0.f ? 3.f : 1.f;
Position.X += Velocity.X * timeStep;
Position.Y += Velocity.Y * timeStep + 1.f / 2.f * gravityScale * Settings->Gravity * timeStep * timeStep;
Velocity.Y += gravityScale * Settings->Gravity * timeStep;
}
void KPawn::CollisionDetectionWithMapStep(const SDL_FRect& map)
{
const auto separationVector = GetCollider()->GetSeparationVector(map);
Position += separationVector;
if (separationVector.Y < 0)
{
Velocity.Y = 0;
CanJump = true;
CanDoubleJump = true;
HasJumped = false;
}
if (separationVector.Y > 0)
{
Velocity.Y = 0;
}
}
void KPawn::AddXMovementInput(const float& input)
{
Velocity.X = input * Constants::SPEED * (1 - Constants::SMOOTH) + Velocity.X * Constants::SMOOTH;
}
void KPawn::StopJump() {
if (!CanJump) {
if (Velocity.Y < -Settings->ShortJumpVelocity)
Velocity.Y = -Settings->ShortJumpVelocity;
}
}
void KPawn::StartJump() {
if (Velocity.Y != 0.f)
{
CanJump = false;
}
if (CanJump) {
CanJump = false;
HasJumped = true;
Velocity.Y = -Settings->JumpInitialVelocity;
}
else if (HasJumped && CanDoubleJump)
{
CanDoubleJump = false;
Velocity.Y = -Settings->JumpInitialVelocity;
}
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <memory>
#include <SDL_rect.h>
#include <unordered_map>
#include "KSolid.h"
#include "Utils.h"
namespace KapitanGame
{
class KSettings;
class KPlayerController;
class KPawn : public KSolid
{
public:
KPawn(const KVector2D& position, const KTexture& texture,
const std::shared_ptr<KPlayerController>& playerController, KSettings* settings)
: KSolid(position, texture, nullptr),
PlayerController(playerController), CanJump(false), CanDoubleJump(false), HasJumped(true), Settings(settings)
{
}
void CollisionDetectionStep(const std::unordered_map<std::pair<int, int>, std::shared_ptr<KSolid>, 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<KPlayerController> PlayerController;
KVector2D Velocity{ 0.f, 0.f };
bool CanJump;
bool CanDoubleJump;
bool HasJumped;
KSettings* Settings;
};
}

View File

@ -0,0 +1,8 @@
#pragma once
namespace KapitanGame {
enum class KPlayer : int {
Player1,
Player2
};
}

View File

@ -0,0 +1,55 @@
#include "KPlayerController.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;
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "KPawn.h"
#include "KPlayer.h"
#include "KVector2d.h"
namespace KapitanGame {
class KInput;
class KPlayerController : public std::enable_shared_from_this<KPlayerController>
{
public:
explicit KPlayerController(const KPlayer player)
: Player(player)
{
}
void SetupInputBindings(KInput& input);
void MoveXAxis(float axis);
void StartJump();
void StopJump();
void Update(float deltaTime);
void Possess(KPawn* pawn);
void UnPossess();
const KPlayer& GetPlayer() const;
private:
KVector2D Input{ 0.f, 0.f };
const KPlayer Player;
KPawn* Pawn{};
bool InputStartJump{};
bool InputStopJump{};
};
typedef void (KPlayerController::* KPlayerCommand)();
typedef void (KPlayerController::* KPlayerAxisCommand)(float input);
}

View File

@ -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<const KCircle*>(other);
if (circle != nullptr)
return IsCollision(circle);
const auto rect = dynamic_cast<const KRect*>(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<const KCircle*>(other);
if (circle != nullptr)
return GetSeparationVector(circle);
const auto rect = dynamic_cast<const KRect*>(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;
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <SDL_rect.h>
#include "KCollider.h"
namespace KapitanGame {
class KCircle;
class KRect final : public KCollider
{
public:
KRect(KSolid* parent, const float width, const float height)
: KCollider(parent),
Width(width),
Height(height)
{
}
[[nodiscard]] float GetWidth() const override;
[[nodiscard]] float GetHeight() const override;
static KVector2D GetSeparationVector(float left, float right, float top, float bottom);
bool IsCollision(const KCollider* other) const override;
KVector2D GetSeparationVector(const KCollider* other) const override;
[[nodiscard]] KVector2D GetSeparationVector(const SDL_FRect& map) const override;
private:
KVector2D GetSeparationVector(const KCircle* other) const;
KVector2D GetSeparationVector(const KRect* other) const;
bool IsCollision(const KCircle* other) const;
[[nodiscard]] float GetLeft() const;
[[nodiscard]] float GetRight() const;
[[nodiscard]] float GetBottom() const;
[[nodiscard]] float GetTop() const;
bool IsCollision(const KRect* other) const;
float Width;
float Height;
};
}

View File

@ -0,0 +1,15 @@
#include "KRectPawn.h"
namespace KapitanGame
{
KRectPawn::KRectPawn(const KVector2D& position, const KTexture& texture,
const std::shared_ptr<KPlayerController>& playerController, KSettings* settings) : KPawn(position, texture, playerController, settings),
Collider(this, texture.GetWidth(), texture.GetHeight())
{
}
const KCollider* KRectPawn::GetCollider() const
{
return &Collider;
}
}

View File

@ -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<KPlayerController>& playerController, KSettings* settings);
const KCollider* GetCollider() const override;
private:
KRect Collider;
};
}

View File

@ -0,0 +1,98 @@
#include "KSettings.h"
#include <algorithm>
#include <cmath>
#include "Constants.h"
namespace KapitanGame
{
KSettings::KSettings(const float maxJumpHeight, const float horizontalDistanceToMaxJumpHeight) : MaxJumpHeightValue(maxJumpHeight),
HorizontalDistanceToMaxJumpHeightValue(horizontalDistanceToMaxJumpHeight),
TimeToMaxHeightValue(NAN),
GravityValue(NAN),
JumpInitialVelocityValue(NAN),
ShortJumpVelocityValue(NAN),
CollisionEnabledValue(true),
Dirty(true),
MaxJumpHeight(this, &KSettings::GetMaxJumpHeight, &KSettings::SetMaxJumpHeight),
HorizontalDistanceToMaxJumpHeight(this, &KSettings::GetHorizontalDistanceToMaxJumpHeight, &KSettings::SetHorizontalDistanceToMaxJumpHeight),
TimeToMaxHeight(this, &KSettings::GetTimeToMaxHeight),
Gravity(this, &KSettings::GetGravity),
JumpInitialVelocity(this, &KSettings::GetJumpInitialVelocity),
ShortJumpVelocity(this, &KSettings::GetShortJumpVelocity),
CollisionEnabled(this, &KSettings::GetCollisionEnabled, &KSettings::SetCollisionEnabled)
{
}
void KSettings::SetCollisionEnabled(const bool value)
{
if (value != CollisionEnabledValue)
CollisionEnabledValue = value;
}
void KSettings::SetMaxJumpHeight(const float h)
{
if (h <= 0.f && MaxJumpHeightValue <= 0.f) return;
if (MaxJumpHeightValue != h) { // NOLINT(clang-diagnostic-float-equal)
MaxJumpHeightValue = std::max(h, 0.f);
Dirty = true;
}
}
void KSettings::SetHorizontalDistanceToMaxJumpHeight(const float xn)
{
if (xn <= 0.f && HorizontalDistanceToMaxJumpHeightValue <= 0.f) return;
if (HorizontalDistanceToMaxJumpHeightValue != xn) { // NOLINT(clang-diagnostic-float-equal)
HorizontalDistanceToMaxJumpHeightValue = std::max(xn, 0.f);
Dirty = true;
}
}
// ReSharper disable once CppMemberFunctionMayBeConst
bool KSettings::GetCollisionEnabled()
{
return CollisionEnabledValue;
}
float KSettings::GetTimeToMaxHeight()
{
if (Dirty)
TimeToMaxHeightValue = HorizontalDistanceToMaxJumpHeightValue / Constants::SPEED;
return TimeToMaxHeightValue;
}
float KSettings::GetGravity()
{
if (Dirty) {
const auto timeToMaxHeight = GetTimeToMaxHeight();
GravityValue = 2.0f * MaxJumpHeightValue / (timeToMaxHeight * timeToMaxHeight);
}
return GravityValue;
}
float KSettings::GetJumpInitialVelocity()
{
if (Dirty)
JumpInitialVelocityValue = 2.0f * MaxJumpHeightValue / GetTimeToMaxHeight();
return JumpInitialVelocityValue;
}
float KSettings::GetShortJumpVelocity()
{
if (Dirty)
ShortJumpVelocityValue = GetJumpInitialVelocity() / 2.f;
return ShortJumpVelocityValue;
}
// ReSharper disable once CppMemberFunctionMayBeConst
float KSettings::GetMaxJumpHeight()
{
return MaxJumpHeightValue;
}
// ReSharper disable once CppMemberFunctionMayBeConst
float KSettings::GetHorizontalDistanceToMaxJumpHeight()
{
return HorizontalDistanceToMaxJumpHeightValue;
}
}

View File

@ -0,0 +1,37 @@
#pragma once
#include "Property.h"
namespace KapitanGame
{
class KSettings final
{
float MaxJumpHeightValue;
float HorizontalDistanceToMaxJumpHeightValue;
float TimeToMaxHeightValue;
float GravityValue;
float JumpInitialVelocityValue;
float ShortJumpVelocityValue;
bool CollisionEnabledValue;
bool Dirty;
public:
KSettings(float maxJumpHeight, float horizontalDistanceToMaxJumpHeight);
const Property<float, KSettings> MaxJumpHeight, HorizontalDistanceToMaxJumpHeight;
const ReadOnlyProperty<float, KSettings> TimeToMaxHeight, Gravity, JumpInitialVelocity, ShortJumpVelocity;
const Property<bool, KSettings> CollisionEnabled;
private:
void SetCollisionEnabled(bool value);
void SetMaxJumpHeight(float h);
void SetHorizontalDistanceToMaxJumpHeight(float xn);
bool GetCollisionEnabled();
float GetTimeToMaxHeight();
float GetGravity();
float GetJumpInitialVelocity();
float GetShortJumpVelocity();
float GetMaxJumpHeight();
float GetHorizontalDistanceToMaxJumpHeight();
};
}

View File

@ -0,0 +1,10 @@
#include "KSolid.h"
#include "KCamera.h"
namespace KapitanGame
{
KSolid::KSolid(const KVector2D& position, const KTexture& texture, SDL_Rect* tileClip, const SDL_RendererFlip flip) : KDrawable(position, texture, tileClip, flip)
{
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <SDL_render.h>
#include "KDrawable.h"
#include "KTexture.h"
#include "KVector2d.h"
namespace KapitanGame
{
class KCamera;
class KCollider;
class KSolid : public KDrawable
{
public:
KSolid(const KVector2D& position, const KTexture& texture, SDL_Rect* tileClip, SDL_RendererFlip flip = SDL_FLIP_NONE);
~KSolid() override = default;
[[nodiscard]] virtual const KCollider* GetCollider() const = 0;
};
}

View File

@ -0,0 +1,9 @@
#include "KSolidTile.h"
namespace KapitanGame
{
const KCollider* KSolidTile::GetCollider() const
{
return &Collider;
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "Constants.h"
#include "KSolid.h"
#include "KRect.h"
namespace KapitanGame
{
class KSolidTile final :
public KSolid
{
public:
KSolidTile(const KVector2D& position, const KTexture& texture, SDL_Rect* tileClip, const SDL_RendererFlip flip = SDL_FLIP_NONE)
: KSolid(position, texture, tileClip, flip),
Collider(this, tileClip != nullptr ? Constants::TILE_WIDTH * 1.f : texture.GetWidth() * 1.f, tileClip != nullptr ? Constants::TILE_HEIGHT * 1.f : texture.GetHeight() * 1.f)
{
}
const KCollider* GetCollider() const override;
private:
KRect Collider;
};
}

View File

@ -0,0 +1,155 @@
#include "KTexture.h"
#include <SDL_image.h>
#include <SDL_render.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;
Free();
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 = IMG_Load(path.c_str());
if (loadedSurface == nullptr)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Color key image
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0xFF, 0, 0xFF));
//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,
static_cast<float>(Width) * scale, static_cast<float>(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, SDL_Rect* clip, const float scale, const SDL_RendererFlip flip) const
{
if (Texture == nullptr) return;
//Set rendering space and render to screen
SDL_FRect renderQuad = {
x * scale, y * scale,
static_cast<float>(Width) * scale, static_cast<float>(Height) * scale
};
//Set clip rendering dimensions
if (clip != nullptr)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopyExF(renderer, Texture, clip, &renderQuad, degrees, nullptr, flip);
}
int KTexture::GetWidth() const
{
return Width;
}
int KTexture::GetHeight() const
{
return Height;
}
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <SDL_render.h>
#include <string>
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 = 0, SDL_Rect* clip = nullptr, float scale = 1.f, SDL_RendererFlip flip = SDL_FLIP_NONE) const;
//Gets image dimensions
int GetWidth() const;
int GetHeight() const;
private:
//The actual hardware texture
SDL_Texture* Texture;
//Image dimensions
int Width;
int Height;
};
}

View File

@ -0,0 +1,33 @@
#include "KTile.h"
#include <SDL_render.h>
#include "Constants.h"
#include "KTexture.h"
namespace KapitanGame {
int KTile::GetType() const {
return static_cast<int>(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);
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <SDL_rect.h>
#include <cstdint>
#include <SDL_render.h>
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;
};
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <cfloat>
#define _USE_MATH_DEFINES
#include <cmath>
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 ;
}
};
}

View File

@ -0,0 +1,8 @@
#include "KGame.h"
int main(int argc, char* args[])
{
KapitanGame::KGame game;
return game.Run(argc, args);
}

View File

@ -0,0 +1,54 @@
#pragma once
namespace KapitanGame
{
template <class T, class C>
class ReadOnlyProperty {
protected:
C* Owner;
T(C::* Getter)();
public:
ReadOnlyProperty() : Owner(), Getter() {}
ReadOnlyProperty(C* owner, T(C::* getter)()) : Owner(owner), Getter(getter) {}
[[nodiscard]] T Get() const {
return (Owner->*Getter)();
}
// ReSharper disable once CppNonExplicitConversionOperator
operator T() const {
return Get();
}
};
template <class T, class C>
class Property : public ReadOnlyProperty<T,C> {
void(C::* Setter)(T);
public:
Property() : ReadOnlyProperty(), Setter() {}
Property(C* owner, T(C::* getter)(), void(C::* setter)(T)) : ReadOnlyProperty<T, C>(owner,getter), Setter(setter) {}
void Set(T value) const {
(this->Owner->*Setter)(value);
}
const Property<T, C>& operator = (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(value);
return *this;
}
const Property<T, C>& operator -= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() - value);
return *this;
}
const Property<T, C>& operator += (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() + value);
return *this;
}
const Property<T, C>& operator *= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() * value);
return *this;
}
const Property<T, C>& operator /= (T value) const { // NOLINT(misc-unconventional-assign-operator)
Set(this->Get() / value);
return *this;
}
};
}

View File

@ -0,0 +1,7 @@
#include "Utils.h"
namespace KapitanGame {
namespace Utils {
}
}

109
2dkg_zad5/2dgk_zad5/Utils.h Normal file
View File

@ -0,0 +1,109 @@
#pragma once
#include <memory>
#include <string>
#include <stdexcept>
#include <random>
#include <unordered_map>
#include "KPlayer.h"
namespace KapitanGame {
namespace Utils {
template<typename ... Args>
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<size_t>(sizeS);
const auto buf = std::make_unique<char[]>(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 <class T>
constexpr const T& Clamp(const T& x, const T& min, const T& max)
{
return std::max(std::min(max, x), min);
}
template <class T>
constexpr const T& Clamp01(const T& x)
{
return Clamp(x, 0.f, 1.f);
}
template <class T>
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<double> dist(0.0, 1.0);
return dist(GetRandomEngine());
}
template <typename C, C BeginVal, C EndVal>
class Iterator {
typedef std::underlying_type_t<C> ValT;
int Value;
public:
explicit Iterator(const C& f) : Value(static_cast<ValT>(f)) {}
Iterator() : Value(static_cast<ValT>(BeginVal)) {}
Iterator operator++() {
++Value;
return *this;
}
C operator*() { return static_cast<C>(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<std::string, KPlayer> 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<KPlayer, KPlayer::Player1, KPlayer::Player1> KPlayerIterator;
struct PairHash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1, T2>& p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
return h1 ^ h2;
}
};
}
}

View File

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

View File

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

BIN
2dkg_zad5/2dgk_zad5/assets/fonts/PressStart2P-Regular.ttf (Stored with Git LFS) Normal file

Binary file not shown.

BIN
2dkg_zad5/2dgk_zad5/assets/fonts/Roboto-Thin.ttf (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,79 @@
#100,15
!0
3 3 3
3 3 3
3 3
g
hg 6g
5hg 6g 67hg
55hg 67hg 6g 6755hg 6
555hg 6755hg67hg 6g 675555hg 67
5555hg 675555h755hg 67hg 67555555hg 675
55555hg 675555555555hg 6755hg 675555555555555555555555555555555555555555555556755
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
!1
44
4 444 44 4 4 4 44 444 4
44444 444 4 444 44 44 4444 4 4 4444 4 4 44 4444444444 4444 444 44
44444 444444444444 4 4444 4444444444444 44444444 4 4444 444444444444 44444444444 4444
4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
!2
2222
222222222222
22222222222222
2222222222222222
22222222222222222
22222222222222222
2222222222 22222222222222222
2222222222 22222222222222222
2222222222 22222222222222222
2222222222 22222222222222222
!3
0000
0000 000
0 000 00
000
000000
0000 0
0 00000 00 00 0
00 00 00 0000 0
00 00 00 00
P 00 00 00 00
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
!4
1111
1111
1 11
11
11111
1111
1 11111 1111111111
11 1111
11
1111111111111111111111111111 11111111 111111 111111 11111111111111111111111111111111111111111111

View File

@ -0,0 +1,15 @@
3333
333344444111
3 33144444444411
3314444444444444
333311444444444444444
3333 14444444444444444
3 33333 3366666633 14444444444444444
33 1144444411 3333 14444444444444444
33 11 1144444411 44444444444444444
P 11 11 1144444411 44444444444444444
3333333333333333333333333333113333333311333333113333331133333333333333333333333333333333333333333333
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

BIN
2dkg_zad5/2dgk_zad5/assets/textures/P1.bmp (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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"
}
]
}
}
}

View File

@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by 2dgk_zad5.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

View File

@ -0,0 +1,11 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"name": "dgk-zad5",
"version": "0.1.0",
"dependencies": [
"sdl2",
"nlohmann-json",
"sdl2-ttf",
"sdl2-image"
]
}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"building","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAsUlEQVRYR2NsbGz8zzCAgHFQOeDOYzZwWKjI/gLThPgV7ivB6jp2hhOlHt08kCaUECBkIbo81R0wEElhaKUBSoOc4jRAcweMpgFSg5hU9QTTAKkGkqqeoANG0wCpRTGl6imuC6jugNE0QGmQkpotqZ4GKHbAaBqgdpOLUJoimAZIjVNCFo7WBdgSOUXNclKDHD1KCaYBUi0gpJ6gA0bLAVKDkNJyg+Q0QKhcICSPrRwAAKcaoHCrImDsAAAAAElFTkSuQmCC\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"cloud","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAsklEQVRYR+2WwRGAIAwE5WcLVmTNVmQL/nR44ACSSY5g+MQ35HbukmBYwO86jzu/sm57AEsUx6HLtXis5ADaOMQRtOynskdiEQEg4glKCsEC9IgjsZAAWuE6HsqRD8BoYS6SF+AvYc6JYCVM9cV8gEg2w4XkiHkP1E1ZTIGlE2kszQDEe0DTE9L1m09EcxP2RjEMoPXKUVA9oqwDml8s9C77GqIF0fMO4A64A+6AOzDdgQdHX0u4c/gHsgAAAABJRU5ErkJggg==\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"grass","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAb0lEQVRYR+2T0QnAIAwFzRpO1VE7lWtYIlhE89FgJT/np5iXy6ly11xT4BIAwg3o9e9AXFJkJ+Mt1iAPSG88vl9vvZ5vAHOIBdP3rMZeiDFjAfjzR85GLPijAF+GAQADGMAABjCAAQxgAAMYCDfwANHJNNEYkYYOAAAAAElFTkSuQmCC\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"ground","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABPElEQVRYR91W2xHCQAg0xWgFtmEF2kx6sQO7sRmdywwZ5JZnEl/+RQ5ugVuWYRzHx0787rer/Gv+Ppwu0Gb5kAPyHc7H/QSAjJFAKGDGj2cwA1BT3tgw8BZUs6hibFX/GABqeRgAf0BrVKoD4AWVL5ifbzbPX2PCXAEvAKIQ+WQYJOO4ADTeWw9PSwbOgcaCyuD5HwA0Ca2Msm2ItIDOhCbhTwHw2CQr3YlROyCDZCqQBoDkWILwAGQvfVFDDUAURPVyqAXWYrJkEZFxeSzIAm20WnqQkWQeP0RDTUiq5X/LRmSJV/cI18jEWjzJhujtqmGlt5qPCQANoMzlfLNGfqjK3U64FESGquoc0JBqfbQ4bvmUAUSBeO0zJ2FWjDIsUndCjvjrAHgc37wCFYqhN6BuxZYKetlnqIsAPAF+tP9L2HSFWAAAAABJRU5ErkJggg==\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"ground2","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABN0lEQVRYR91WyRHDMAiUC/XPTaQCN5FfCk1GmcFD0HLazpWfg0ALaFmmeVnvTfxu14v8a/uelxXaLB9yQL5Ta+0JgIyRQChgxo9nsAFQUz7ZMPEWVLOoYuxV/xgAankYAH9AR1RqAOAFlS+Yn+82z19jwlYBLwCiEPlkGCTjuAA03lsPT0sGzoHOgsrg+R8ANAmtjLJtiLSAzoQm4U8B8NgkKz2IUT8gg2QqkAaA5FiC8ABkL31RQw1AFET1cqgF1mKyZxGRcXksyAJttFp6kJFkHj9EQ01IquV/y0ZkidfwCI/IxFo8yYbo7aphpbeajwkADaDM5XyzRn6oysNOuBdEhqrqHNCQan20OG75lAFEgXjtMydhVowyLFJ3Qo746wB4HD+9AhWKoTegbsWWCnrZZ6iLADwAcfPzMd769scAAAAASUVORK5CYII=\"}]}"]}}

BIN
2dkg_zad5/assets_src/maptiles.psd (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"mountain","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAANElEQVRYR+3QQREAAAQAQcJooI3+OYjhs5fgZnO6Nh5LAwQIECBAgAABAgQIECBAgMC3wAGoHDaB0QshaAAAAABJRU5ErkJggg==\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"mountain2","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+WXyQ2AIBBFpR3L8myhtmQ8aCAhMQjM+jFRC+D9ZVgM0+Bv3+bzjgyj+CU4c+ECWuB/CKDcxxSgFfQELOuRWoAJaMEzGDoDHOevCCjdQyrgRg9LoCag5hwiQOretQIN/DsCJNuuvPxcDiJt/C4VWOAwAb1t51qB1b0pAcvgmZ5k1B0viV+VgJdz8VFMOY8LSt2zE6DgGrAoAe/Y2UOIdE4mMALenIFR8IcACqyd9N7vX+BA8wKWaW+JYAtAwFMFnARQ8CjgApWjjZRhAQvBAAAAAElFTkSuQmCC\"}]}"]}}

View File

@ -0,0 +1 @@
{"modelVersion":2,"piskel":{"name":"mountain3","description":"","fps":12,"height":32,"width":32,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":1,\"chunks\":[{\"layout\":[[0]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAWklEQVRYR2P8eULrPwMBkJTzm5ASsuUZB7UDaOlzWJBhDQF6WIzTAfS0HOQIxmgTVYKJkOwURoTGUQeMhsBoCIyGwGgIjIbAaAiMhsBoCIyGwGgIjIbAaAgAAGaSRYF+p7PUAAAAAElFTkSuQmCC\"}]}"]}}

16
2dkg_zad5/readme.txt Normal file
View File

@ -0,0 +1,16 @@
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).
Sterowanie (możliwa zmiana w config.json):
AD/lewa gałka pada - ruch poziomy
Spacja/A na padzie - skok
F1 - tryb deweloperski
F2 (w trybie deweloperskim) - wł./wył. kolizji
F3/F4 - (w trybie deweloperskim) - zwiększ/zmiejsz maksymalną wysokość skoku.
F5/F6 - (w trybie deweloperskim) - zwiększ/zmiejsz maksymalną odległość poziomą skoku
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