Zad2 final

This commit is contained in:
Michał Leśniak 2021-12-12 13:40:09 +01:00
parent 7faaf63fb5
commit 4960cdb39b
53 changed files with 1632 additions and 488 deletions

1
.gitattributes vendored
View File

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

101
2dgk_7/2dgk_7/2dgk_7.rc Normal file
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_7.exe"
VALUE "LegalCopyright", "Copyright (C) 2021 Michał Leśniak"
VALUE "OriginalFilename", "2dgk_7.exe"
VALUE "ProductName", "2DKG_7"
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

@ -154,13 +154,21 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="KCamera.cpp" />
<ClCompile Include="KCircle.cpp" />
<ClCompile Include="KCirclePawn.cpp" />
<ClCompile Include="KExit.cpp" />
<ClCompile Include="KFont.cpp" />
<ClCompile Include="KGame.cpp" />
<ClCompile Include="KInput.cpp" />
<ClCompile Include="KObject.cpp" />
<ClCompile Include="KPawn.cpp" />
<ClCompile Include="KPlayerController.cpp" />
<ClCompile Include="KRect.cpp" />
<ClCompile Include="KShape.cpp" />
<ClCompile Include="KCollider.cpp" />
<ClCompile Include="KRectPawn.cpp" />
<ClCompile Include="KTexture.cpp" />
<ClCompile Include="KWall.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
@ -172,17 +180,29 @@
<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="KExit.h" />
<ClInclude Include="KFont.h" />
<ClInclude Include="KGame.h" />
<ClInclude Include="KInput.h" />
<ClInclude Include="KObject.h" />
<ClInclude Include="KPawn.h" />
<ClInclude Include="KPlayer.h" />
<ClInclude Include="KPlayerController.h" />
<ClInclude Include="KRect.h" />
<ClInclude Include="KShape.h" />
<ClInclude Include="KCollider.h" />
<ClInclude Include="KRectPawn.h" />
<ClInclude Include="KTexture.h" />
<ClInclude Include="KWall.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="KVector2d.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2dgk_7.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -36,12 +36,36 @@
<ClCompile Include="KPlayerController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KShape.cpp">
<ClCompile Include="KCollider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KRect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KObject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KPawn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KWall.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="KExit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KCamera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KFont.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="vcpkg.json" />
@ -74,7 +98,7 @@
<ClInclude Include="KPlayerController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KShape.h">
<ClInclude Include="KCollider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KRect.h">
@ -89,5 +113,37 @@
<ClInclude Include="KPlayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KObject.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KPawn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KWall.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="KExit.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>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2dgk_7.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -11,8 +11,7 @@ namespace KapitanGame {
constexpr float SCREEN_RATIO = static_cast<float>(SCREEN_WIDTH) / SCREEN_HEIGHT;
constexpr int TILE_WIDTH = 32;
constexpr int TILE_HEIGHT = 32;
constexpr float SPEED = 0.16f;
constexpr float SPEED = 200.f;
constexpr float SMOOTH = 0.4f;
constexpr int CIRCLES_COUNT = 100;
}
}

View File

@ -10,20 +10,20 @@ namespace KapitanGame {
Hold
};
struct KActionBind {
KActionBind(std::string name, const InputState expectedInputState, KPlayerController* controllerObject, const KPlayerCommand command, const KPlayer player) :
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;
KPlayerController* ControllerObject;
std::weak_ptr<KPlayerController> ControllerObject;
KPlayerCommand Command;
KPlayer Player;
};
struct KAxisBind
{
KAxisBind(std::string name, KPlayerController* controllerObject, const KPlayerAxisCommand command, const KPlayer player) :
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;
KPlayerController* ControllerObject;
std::weak_ptr<KPlayerController> ControllerObject;
KPlayerAxisCommand AxisCommand;
KPlayer Player;
};

42
2dgk_7/2dgk_7/KCamera.cpp Normal file
View File

@ -0,0 +1,42 @@
#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::shared_ptr<KPawn>& playerOne, const std::shared_ptr<KPawn>& playerTwo, const SDL_FRect& map)
{
FocusPoint = (playerOne->GetPosition() + playerTwo->GetPosition()) * 0.5f;
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 = Constants::SCREEN_RATIO > 1.f ? Constants::SCREEN_HEIGHT * 1.f / map.h : Constants::SCREEN_WIDTH * 1.f / map.w;
}
const SDL_FRect& KCamera::GetPlayArea() const
{
return PlayArea;
}
}

42
2dgk_7/2dgk_7/KCamera.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include <memory>
#include <SDL_rect.h>
#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::shared_ptr<KPawn>& playerOne, const std::shared_ptr<KPawn>& playerTwo, 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

@ -1,70 +1,106 @@
#include "KCircle.h"
#include <stdexcept>
#include "KRect.h"
#include "Utils.h"
namespace KapitanGame {
KCircle::KCircle(const KVector2D& position, const KVector2D& velocity, const float& radius, const KTexture& texture) : KShape(position, velocity, texture),
Radius(radius) {
bool KCircle::IsCollision(const KCircle* other) const {
return (GetParent()->GetPosition() - other->GetParent()->GetPosition()).Length() < Radius + other->Radius;
}
bool KCircle::IsCollision(const KCircle& other) const {
return (Position - other.Position).Length() < Radius + other.Radius;
bool KCircle::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");
}
bool KCircle::IsCollision(const KRect& other) const {
const auto f = KVector2D(Utils::Clamp(Position.X, other.GetPosition().X - other.GetWidth() / 2, other.GetPosition().X + other.GetWidth() / 2),
Utils::Clamp(Position.Y, other.GetPosition().Y - other.GetHeight() / 2, other.GetPosition().Y + other.GetHeight() / 2));
KVector2D KCircle::GetSeparationVector(const KCollider* other) const
{
const auto circle = dynamic_cast<const KCircle*>(other);
if (circle != nullptr)
return GetSeparationVector(circle);
return (Position - f).Length() < Radius;
const auto rect = dynamic_cast<const KRect*>(other);
if (rect != nullptr)
return GetSeparationVector(rect);
throw std::runtime_error("unsupported shape");
}
KVector2D KCircle::GetSeparationVector(const KCircle& other) const {
const KVector2D centerDiff = Position - other.Position;
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);
return centerDiff / centerDiffLength * (Radius + other->Radius - centerDiffLength);
}
KVector2D KCircle::GetSeparationVector(const KRect& other) const {
const float l = other.GetPosition().X - other.GetWidth() / 2;
const float r = other.GetPosition().X + other.GetWidth() / 2;
const float t = other.GetPosition().Y - other.GetHeight() / 2;
const float b = other.GetPosition().Y + other.GetHeight() / 2;
const auto f = KVector2D(Utils::Clamp(Position.X, l, r),
Utils::Clamp(Position.Y, t, b));
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 (Position == f) {
const auto left = Position.X - l + Radius;
const auto right = r - Position.X + Radius;
const auto top = Position.Y - t + Radius;
const auto bottom = b - Position.Y + Radius;
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 (Position - f) / (Position - f).Length() * (Radius - (Position - f).Length());
return (GetParent()->GetPosition() - f) / (GetParent()->GetPosition() - f).Length() * (Radius - (GetParent()->GetPosition() - f).Length());
}
void KCircle::CollisionDetectionWithMapStep(const SDL_Rect& map) {
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;
}
if (Position.X - map.x - Radius < 0)
{
Position.X += -(Position.X - map.x - Radius);
Velocity = Velocity.Reflect({ -1.f, 0.f });
}
if (Position.X + Radius - map.w > 0)
{
Velocity = Velocity.Reflect({ 1.f, 0.f });
Position.X += -(Position.X - map.w + Radius);
}
if (Position.Y - Radius - map.y < 0) {
Position.Y += -(Position.Y - map.y - Radius);
Velocity = Velocity.Reflect({ 0.f, 1.f });
}
if (Position.Y + Radius - map.h > 0) {
Position.Y += -(Position.Y - map.h + Radius);
Velocity = Velocity.Reflect({ 0.f, -1.f });
}
float KCircle::GetWidth() const
{
return Radius * 2;
}
float KCircle::GetHeight() const
{
return Radius * 2;
}
KCircle::KCircle(KObject* parent, const float radius): KCollider(parent),
Radius(radius)
{
}
float KCircle::GetRadius() const {

View File

@ -1,21 +1,29 @@
#pragma once
#include "KShape.h"
#include "KTexture.h"
#include <SDL_rect.h>
#include "KCollider.h"
#include "KVector2d.h"
namespace KapitanGame {
class KCircle final : public KShape
class KRect;
class KCircle final : public KCollider
{
public:
KCircle(const KVector2D& position, const KVector2D& velocity, const float& radius, const KTexture& texture);
void CollisionDetectionWithMapStep(const SDL_Rect& map) override;
KCircle(KObject* parent, const float radius);
float GetRadius() const;
protected:
KVector2D GetSeparationVector(const KCircle& other) const override;
KVector2D GetSeparationVector(const KRect& other) const override;
bool IsCollision(const KCircle& other) const override;
bool IsCollision(const KRect& other) const override;
private:
KVector2D GetSeparationVector(const KCircle* other) const;
KVector2D GetSeparationVector(const KRect* other) const;
bool IsCollision(const KCircle* other) const;
bool IsCollision(const KRect* other) const;
public:
bool IsCollision(const KCollider* other) const override;
KVector2D GetSeparationVector(const KCollider* other) const override;
KVector2D GetSeparationVector(const SDL_FRect& map) const override;
float GetWidth() const override;
float GetHeight() const override;
private:
float Radius{ 1.f };
};

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) : KPawn(position, texture, playerController),
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);
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(KObject* parent): Parent(parent)
{
}
KObject* KCollider::GetParent() const
{
return Parent;
}
}

35
2dgk_7/2dgk_7/KCollider.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include <SDL_rect.h>
#include "KObject.h"
#include "KVector2d.h"
namespace KapitanGame {
class KCollider
{
public:
KCollider(const KCollider& other);
KCollider(KCollider&& other) noexcept;
KCollider& operator=(const KCollider& other);
KCollider& operator=(KCollider&& other) noexcept;
explicit KCollider(KObject* parent);
virtual ~KCollider() = default;
virtual bool IsCollision(const KCollider* other) const = 0;
virtual KVector2D GetSeparationVector(const KCollider* other) const = 0;
virtual KVector2D GetSeparationVector(const SDL_FRect& map) const = 0;
virtual float GetWidth() const = 0;
virtual float GetHeight() const = 0;
KObject* GetParent() const;
private:
KObject* Parent;
};
}

9
2dgk_7/2dgk_7/KExit.cpp Normal file
View File

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

22
2dgk_7/2dgk_7/KExit.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "KObject.h"
#include "KRect.h"
namespace KapitanGame
{
class KExit final :
public KObject
{
public:
KExit(const KVector2D& position, const KTexture& texture)
: KObject(position, texture),
Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f)
{
}
const KCollider* GetCollider() const override;
private:
KRect Collider;
};
}

63
2dgk_7/2dgk_7/KFont.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "KFont.h"
#include "KTexture.h"
namespace KapitanGame
{
KFont::KFont()
= default;
KFont::~KFont()
{
Free();
}
KFont::KFont(KFont&& other) noexcept : Font(other.Font)
{
other.Font = nullptr;
}
KFont& KFont::operator=(KFont&& other) noexcept
{
Font = other.Font;
other.Font = nullptr;
return *this;
}
bool KFont::LoadFromFile(const std::string& path, const int ptSize)
{
bool success = true;
Font = TTF_OpenFont(path.c_str(), ptSize);
if (Font == nullptr)
{
printf("Failed to load %s font! SDL_ttf Error: %s\n", path.c_str(), TTF_GetError());
success = false;
}
return success;
}
void KFont::Free()
{
if (Font != nullptr)
{
TTF_CloseFont(Font);
Font = nullptr;
}
}
KTexture KFont::GetTextTexture(const std::string& text, const SDL_Color textColor, SDL_Renderer* renderer) const
{
KTexture texture;
SDL_Surface* textSurface = TTF_RenderText_Blended(Font, text.c_str(), textColor);
if (textSurface == nullptr)
{
printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
}
else
{
texture.LoadFromSurface(textSurface, renderer);
SDL_FreeSurface(textSurface);
}
return texture;
}
}

36
2dgk_7/2dgk_7/KFont.h Normal file
View File

@ -0,0 +1,36 @@
#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;
private:
//The actual hardware font
TTF_Font* Font{};
};
}

View File

@ -1,20 +1,29 @@
#include "KGame.h"
#include "SDL.h"
#include <SDL_ttf.h>
#include <nlohmann/json.hpp>
#include <cstdio>
#include <cmath>
#include <string>
#include <fstream>
#include <vector>
#include "Utils.h"
#include "Constants.h"
#include "KCamera.h"
#include "KCirclePawn.h"
#include "KExit.h"
#include "KRectPawn.h"
#include "KTexture.h"
#include "KTile.h"
#include "KVector2d.h"
#include "KWall.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace KapitanGame {
KGame::KGame() : HasSeparation(true), HasCollision(true) {
KGame::KGame() : Time(0), PreviousTime(0), Map()
{
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
@ -28,8 +37,14 @@ namespace KapitanGame {
Input.Init();
if (TTF_Init() < 0)
{
throw std::runtime_error(Utils::StringFormat("SDL_TTF could not initialize! TTF_Error: %s", TTF_GetError()));
}
//Create window
Window = SDL_CreateWindow(Constants::WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
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()));
@ -38,7 +53,8 @@ namespace KapitanGame {
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()));
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);
@ -46,9 +62,12 @@ namespace KapitanGame {
KGame::~KGame() {
//Free loaded images
CircleTexture.Free();
Textures.clear();
Objects.clear();
Pawns.clear();
PlayerControllers.clear();
Fonts.clear();
TTF_Quit();
Input.Free();
//Destroy window
@ -61,31 +80,165 @@ namespace KapitanGame {
SDL_Quit();
}
void KGame::Win(KPlayer player)
{
++Scores[static_cast<int>(player)];
Playing = false;
for (const auto& pc : PlayerControllers)
{
pc->UnPossess();
}
Textures.erase("Text_Score");
Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextTexture(Utils::StringFormat("%d:%d", Scores[0], Scores[1]), { 0,0,0,0xFF }, Renderer));
if (++LvlCounter > 3)
{
int max = Scores[0];
auto winner = KPlayer::Player1;
for (int i = 1; i < static_cast<int>(KPlayer::Player2) + 1; ++i)
{
if (max < Scores[i])
{
max = Scores[i];
winner = static_cast<KPlayer>(i);
}
}
ShowWinner = true;
Textures.erase("Text_Winner");
Textures.emplace("Text_Winner", Fonts["Roboto-Thin"].GetTextTexture(Utils::StringFormat("Player %d won!", static_cast<int>(winner) + 1), { 0,0,0,0xFF }, Renderer));
LvlCounter = 1;
}
RestartTick = Time + 5000;
}
bool KGame::LoadLevel()
{
bool success = true;
Objects.clear();
FreePositions.clear();
std::ifstream levelFile;
levelFile.open("assets/levels/level" + std::to_string(LvlCounter) + ".txt");
if (levelFile.fail())
{
printf("Failed to load assets/levels/level%d.txt!\n", LvlCounter);
success = false;
}
else
{
int y = 0;
float mapWidth = 0;
std::string line;
while (std::getline(levelFile, line)) {
if (mapWidth < static_cast<float>(line.length() * Constants::TILE_WIDTH))
mapWidth = static_cast<float>(line.length()) * Constants::TILE_WIDTH;
for (auto i = 0ull; i < line.length(); ++i) {
KVector2D position{ static_cast<float>(i * Constants::TILE_WIDTH + Constants::TILE_WIDTH / 2) , static_cast<float>(y * Constants::TILE_HEIGHT + Constants::TILE_HEIGHT / 2) };
switch (line[i])
{
case '#':
Objects.emplace_back(std::make_shared<KWall>(position, Textures["wall.bmp"]));
break;
case ' ':
FreePositions.emplace_back(position);
break;
default:
break;
}
}
++y;
}
const auto mapHeight = static_cast<float>(y * Constants::TILE_HEIGHT);
levelFile.close();
Map = { 0,0,mapWidth,mapHeight };
}
return success;
}
void KGame::LoadPlayerPawnsAndExit()
{
Pawns.clear();
std::shuffle(FreePositions.begin(), FreePositions.end(), Utils::GetRandomEngine());
Objects.emplace_back(std::make_shared<KExit>(FreePositions.back(), Textures["exit.bmp"]));
Exit = Objects.back();
FreePositions.pop_back();
Pawns.emplace_back(std::make_shared<KCirclePawn>(FreePositions.back(), Textures["P1.bmp"], PlayerControllers[static_cast<int>(KPlayer::Player1)]));
FreePositions.pop_back();
PlayerControllers[static_cast<int>(KPlayer::Player1)]->Possess(Pawns.back().get());
const auto distMax = KVector2D(Constants::TILE_WIDTH * 5, Constants::TILE_HEIGHT * 5);
do
{
auto diff = FreePositions.back() - Pawns.back()->GetPosition();
if (diff.X < 0)
diff.X *= -1.f;
if (diff.Y < 0)
diff.Y *= -1.f;
if (distMax.X - diff.X < 0 || distMax.Y - diff.Y < 0)
{
FreePositions.pop_back();
}
else
{
break;
}
} while (!FreePositions.empty());
Pawns.emplace_back(std::make_shared<KRectPawn>(FreePositions.back(), Textures["P2.bmp"], PlayerControllers[static_cast<int>(KPlayer::Player2)]));
FreePositions.pop_back();
PlayerControllers[static_cast<int>(KPlayer::Player2)]->Possess(Pawns.back().get());
}
bool KGame::LoadMedia()
{
//Loading success flag
bool success = true;
if (!PlayerTexture.LoadFromFile("assets/textures/P1.bmp", Renderer))
for (auto player : Utils::KPlayerIterator())
{
printf("Failed to load player texture image!\n");
success = false;
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, this));
PlayerControllers.back()->SetupInputBindings(Input);
}
if (!PlayerTexture2.LoadFromFile("assets/textures/P2.bmp", Renderer))
{
printf("Failed to load player texture image!\n");
success = false;
}
if (!WallTexture.LoadFromFile("assets/textures/wall.bmp", Renderer))
Textures.emplace("wall.bmp", KTexture());
if (!Textures["wall.bmp"].LoadFromFile("assets/textures/wall.bmp", Renderer))
{
printf("Failed to load wall texture image!\n");
Textures.erase("wall.bmp");
success = false;
}
if (!ExitTexture.LoadFromFile("assets/textures/exit.bmp", Renderer))
Textures.emplace("exit.bmp", KTexture());
if (!Textures["exit.bmp"].LoadFromFile("assets/textures/exit.bmp", Renderer))
{
printf("Failed to load exit texture image!\n");
Textures.erase("exit.bmp");
success = false;
}
Textures.emplace("arrow.bmp", KTexture());
if (!Textures["arrow.bmp"].LoadFromFile("assets/textures/arrow.bmp", Renderer))
{
printf("Failed to load arrow texture image!\n");
Textures.erase("arrow.bmp");
success = false;
}
Fonts.emplace("Roboto-Thin", KFont());
if (!Fonts["Roboto-Thin"].LoadFromFile("assets/fonts/Roboto-Thin.ttf", 72))
{
printf("Failed to load Roboto-Thin font!\n");
Fonts.erase("Roboto-Thin");
success = false;
}
Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextTexture("0:0", { 0,0,0,0xFF }, Renderer));
Textures.emplace("Text_Winner", KTexture());
std::ifstream configFile("config.json");
if (configFile.fail()) {
@ -106,68 +259,11 @@ namespace KapitanGame {
}
}
}
Tiles.clear();
std::ifstream levelFile;
levelFile.open("assets/level1.txt");
if (levelFile.fail())
{
printf("Failed to load assets/level1.txt!\n");
if (!LoadLevel())
success = false;
}
else
{
int y = 0;
std::string line;
while (std::getline(levelFile, line)) {
if (MapWidth < static_cast<int>(line.length() * Constants::TILE_WIDTH))
MapWidth = static_cast<int>(line.length()) * Constants::TILE_WIDTH;
for (auto i = 0ull; i < line.length(); ++i) {
auto type = TileType::Default;
switch (line[i])
{
case '#':
type = TileType::Wall;
break;
default:
continue;
}
Tiles.emplace_back(i * Constants::TILE_WIDTH, y * Constants::TILE_HEIGHT, type);
}
++y;
}
MapHeight = y * Constants::TILE_HEIGHT;
levelFile.close();
}
return success;
}
SDL_Texture* KGame::LoadTexture(const std::string& path) const {
//The final optimized image
SDL_Texture* newTexture = nullptr;
//Load image at specified path
SDL_Surface* loadedSurface = SDL_LoadBMP(path.c_str());
if (loadedSurface == nullptr)
{
printf("Unable to load image %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
else
{
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface(Renderer, loadedSurface);
if (newTexture == nullptr)
{
printf("Unable to optimize image %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
return newTexture;
}
int KGame::Run(int argc, char* args[])
{
//Load media
@ -183,21 +279,24 @@ namespace KapitanGame {
//Event handler
SDL_Event e;
SDL_Rect map{ 0,0,Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT };
KCamera camera(Map);
KCamera debugCamera(Map);
debugCamera.SetDebug(Map);
for (int i = 0; i < Constants::CIRCLES_COUNT; ++i) {
KVector2D position(Utils::RandomNumber() * (Constants::SCREEN_WIDTH - 2 * CircleTexture.GetWidth()) + CircleTexture.GetWidth(), Utils::RandomNumber() * (Constants::SCREEN_HEIGHT - 2 * CircleTexture.GetHeight()) + CircleTexture.GetHeight());
Circles.emplace_back(position, KVector2D(100.f, 100.f), CircleTexture.GetWidth() / 2, CircleTexture);
}
uint32_t previousTime;
uint32_t time = previousTime = SDL_GetTicks();
bool debug = false;
LoadPlayerPawnsAndExit();
camera.Update(Pawns[static_cast<int>(KPlayer::Player1)], Pawns[static_cast<int>(KPlayer::Player2)], Map);
Time = PreviousTime = SDL_GetTicks();
printf("\n");
//While application is running
while (!quit)
{
previousTime = time;
time = SDL_GetTicks();
PreviousTime = Time;
Time = SDL_GetTicks();
float deltaTime = (Time - PreviousTime) * 0.001f;
Input.HandleInputPreEvents();
@ -212,33 +311,116 @@ namespace KapitanGame {
}
Input.HandleEvent(e);
}
Input.HandleInputPostEvents();
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_S) || Input.IsControllerButtonPressed(Controllers::Controller1, SDL_CONTROLLER_BUTTON_START))
Input.HandleInputPostEvents(Playing);
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F1))
{
HasSeparation = !HasSeparation;
debug = !debug;
}
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_C) || Input.IsControllerButtonPressed(Controllers::Controller1, SDL_CONTROLLER_BUTTON_BACK))
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2))
{
HasCollision = !HasCollision;
CollisionEnabled = !CollisionEnabled;
}
if (Playing) {
for (const auto& pc : PlayerControllers) {
pc->Update(deltaTime);
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->MovementStep(deltaTime);
}
if (CollisionEnabled) {
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionStep(Objects);
}
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionWithMapStep(Map);
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionWithMapStep(camera.GetPlayArea());
}
for (auto& circle : Circles)
circle.CollisionDetectionStep(Circles, HasSeparation, HasCollision);
camera.Update(Pawns[static_cast<int>(KPlayer::Player1)], Pawns[static_cast<int>(KPlayer::Player2)], Map);
for (auto& circle : Circles)
circle.CollisionDetectionWithMapStep(map);
}
if (!Playing)
{
if (Time > RestartTick)
{
LoadLevel();
LoadPlayerPawnsAndExit();
debugCamera.SetDebug(Map);
camera.Update(Pawns[static_cast<int>(KPlayer::Player1)], Pawns[static_cast<int>(KPlayer::Player2)], Map);
if (ShowWinner)
{
for (auto i : Utils::KPlayerIterator())
{
Scores[static_cast<int>(i)] = 0;
}
Textures.erase("Text_Score");
Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextTexture(Utils::StringFormat("%d:%d", Scores[0], Scores[1]), { 0,0,0,0xFF }, Renderer));
ShowWinner = false;
}
Playing = true;
continue;
}
}
for (auto& circle : Circles)
circle.MovementStep(static_cast<float>(time - previousTime) / 1000.f);
//Clear screen
SDL_SetRenderDrawColor(Renderer, 0, 0xFF, 0, 0xFF);
SDL_SetRenderDrawColor(Renderer, 66, 135, 245, 0xFF);
SDL_RenderClear(Renderer);
for (auto& circle : Circles)
circle.Render(Renderer);
const auto& cameraInUse = debug ? debugCamera : camera;
if (Playing) {
for (const auto& object : Objects)
object->Render(Renderer, cameraInUse);
for (const auto& pawn : Pawns) {
pawn->Render(Renderer, cameraInUse);
}
if (const auto exit = Exit.lock()) {
const float exitX = camera.GetViewport().x + Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f - exit->GetPosition().X+exit->GetCollider()->GetWidth()/2.f;
const float exitY = camera.GetViewport().y + 25.f - exit->GetPosition().Y + exit->GetCollider()->GetHeight() / 2.f;
const double degrees = atan2(-exitX, exitY) * (180.f / M_PI);
Textures["arrow.bmp"].RenderEx(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f, 25.f, degrees);
}
}
if (ShowWinner)
{
Textures["Text_Winner"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Winner"].GetWidth() / 2.f, 25.f);
}
Textures["Text_Score"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Score"].GetWidth() / 2.f, Constants::SCREEN_HEIGHT - 10.f - Textures["Text_Score"].GetHeight());
if (debug)
{
SDL_SetRenderDrawColor(Renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderDrawLineF(Renderer, 0, Constants::SCREEN_HEIGHT / 2.f, Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT / 2.f);
SDL_RenderDrawLineF(Renderer, Constants::SCREEN_WIDTH / 2.f, 0, Constants::SCREEN_WIDTH / 2.f, Constants::SCREEN_HEIGHT);
SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderDrawPointF(Renderer, camera.GetFocusPoint().X * debugCamera.GetScale(), camera.GetFocusPoint().Y * debugCamera.GetScale());
SDL_SetRenderDrawColor(Renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_FRect debugViewport = { camera.GetViewport().x * debugCamera.GetScale(),
camera.GetViewport().y * debugCamera.GetScale(),
camera.GetViewport().w * debugCamera.GetScale(),
camera.GetViewport().h * debugCamera.GetScale() };
SDL_RenderDrawRectF(Renderer, &debugViewport);
SDL_FRect debug2Viewport = { camera.GetPlayArea().x * debugCamera.GetScale(),
camera.GetPlayArea().y * debugCamera.GetScale(),
camera.GetPlayArea().w * debugCamera.GetScale(),
camera.GetPlayArea().h * debugCamera.GetScale() };
SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderDrawRectF(Renderer, &debug2Viewport);
}
//Update screen
SDL_RenderPresent(Renderer);
@ -247,4 +429,4 @@ namespace KapitanGame {
return 0;
}
}
}

View File

@ -1,19 +1,24 @@
#pragma once
#include <memory>
#include "KTexture.h"
#include <vector>
#include <SDL_render.h>
#include "KCircle.h"
#include "KFont.h"
#include "KInput.h"
namespace KapitanGame {
class KExit;
class KObject;
class KGame
{
public:
KGame();
~KGame();
void Win(KPlayer player);
KGame(const KGame& other) = delete;
KGame(KGame&& other) noexcept = delete;
KGame& operator=(const KGame& other) = delete;
@ -24,16 +29,28 @@ namespace KapitanGame {
SDL_Renderer* Renderer = nullptr;
KTexture CircleTexture;
std::vector<KCircle> Circles;
std::vector<std::shared_ptr<KObject>> 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;
std::vector<KVector2D> FreePositions;
KInput Input;
bool HasSeparation;
bool HasCollision;
private:
uint32_t Time;
uint32_t PreviousTime;
SDL_FRect Map;
bool CollisionEnabled = true;
bool ShowWinner = false;
std::weak_ptr<KObject> Exit;
bool LoadLevel();
void LoadPlayerPawnsAndExit();
bool LoadMedia();
SDL_Texture* LoadTexture(const std::string& path) const;
int LvlCounter = 1;
bool Playing = true;
uint32_t RestartTick = -1;
short Scores[static_cast<int>(KPlayer::Player2) + 1] = { 0,0 };
};
}

View File

@ -74,12 +74,14 @@ namespace KapitanGame {
}
LastKeyboardInputs = KeyboardInputs;
}
void KInput::HandleInputPostEvents() {
void KInput::HandleInputPostEvents(const bool processInput) {
int size = 0;
const Uint8* currentKeyStates = SDL_GetKeyboardState(&size);
KeyboardInputs = std::vector<Uint8>(currentKeyStates, currentKeyStates + size);
ProcessActions();
ProcessAxes();
if (processInput) {
ProcessActions();
ProcessAxes();
}
}
void KInput::HandleEvent(const SDL_Event& event) {
switch (event.type) {
@ -123,12 +125,12 @@ namespace KapitanGame {
}
void KInput::BindAction(const std::string& name, InputState expectedInputState,
KPlayerController* controllerObject,
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, KPlayerController* controllerObject, KPlayerAxisCommand command, KPlayer 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);
}
@ -181,7 +183,8 @@ namespace KapitanGame {
void KInput::ProcessActions() {
for (auto& action : Actions) {
if (CheckAction(action.Name, action.ExpectedInputState, action.Player)) {
std::invoke(action.Command, action.ControllerObject);
if (auto obj = action.ControllerObject.lock())
std::invoke(action.Command, obj);
}
}
}
@ -189,7 +192,8 @@ namespace KapitanGame {
void KInput::ProcessAxes()
{
for (auto& axis : Axes) {
std::invoke(axis.AxisCommand, axis.ControllerObject, GetAxisValue(axis.Name, axis.Player));
if (auto obj = axis.ControllerObject.lock())
std::invoke(axis.AxisCommand, obj, GetAxisValue(axis.Name, axis.Player));
}
}

View File

@ -3,13 +3,14 @@
#include <unordered_map>
#include <vector>
#include "Controllers.h"
#include "GamePad.h"
#include "KActionBind.h"
#include "KPlayer.h"
namespace KapitanGame {
struct KControllerAxisMapping {
KControllerAxisMapping(Controllers controller, SDL_GameControllerAxis axis, float scale) : Controller(controller), Axis(axis), Scale(scale) {}
KControllerAxisMapping(const Controllers controller, const SDL_GameControllerAxis axis, const float scale) : Controller(controller), Axis(axis), Scale(scale) {}
Controllers Controller;
SDL_GameControllerAxis Axis;
float Scale;
@ -29,6 +30,22 @@ namespace KapitanGame {
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;
@ -38,21 +55,6 @@ namespace KapitanGame {
bool IsKeyboardButtonPressed(Uint8 scanCode) const;
bool IsKeyboardButtonReleased(Uint8 scanCode) const;
float GetAxisValue(const std::string& name, const KPlayer& player) const;
void ProcessActions();
void ProcessAxes();
public:
KInput();
void Init();
void Free();
void HandleInputPreEvents();
void HandleInputPostEvents();
void HandleEvent(const SDL_Event& event);
void BindAction(const std::string& name, InputState expectedInputState, KPlayerController* controllerObject, KPlayerCommand command, KPlayer player);
void BindAxis(const std::string& name, 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);
};
}

23
2dgk_7/2dgk_7/KObject.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "KObject.h"
#include "KCamera.h"
namespace KapitanGame
{
std::atomic<int> KObject::IdCounter{ 0 };
KObject::KObject(const KVector2D& position, const KTexture& texture) :
Id(++IdCounter), Position(position), Texture(texture)
{
}
void KObject::Render(SDL_Renderer* renderer, const KCamera& camera) const
{
Texture.Render(renderer, Position.X - Texture.GetWidth() / 2.f - camera.GetViewport().x, Position.Y - Texture.GetHeight() / 2.f - camera.GetViewport().y, nullptr, camera.GetScale());
}
KVector2D KObject::GetPosition() const
{
return Position;
}
}

28
2dgk_7/2dgk_7/KObject.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <atomic>
#include "KTexture.h"
#include "KVector2d.h"
namespace KapitanGame
{
class KCamera;
class KCollider;
class KObject
{
public:
KObject(const KVector2D& position, const KTexture& texture);
virtual ~KObject() = default;
void Render(SDL_Renderer* renderer, const KCamera& camera) const;
KVector2D GetPosition() const;
virtual const KCollider* GetCollider() const = 0;
const int Id;
static std::atomic<int> IdCounter;
protected:
KVector2D Position{ 0.f, 0.f };
private:
const KTexture& Texture;
};
}

46
2dgk_7/2dgk_7/KPawn.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "KPawn.h"
#include <memory>
#include <typeinfo>
#include "Constants.h"
#include "KPlayerController.h"
#include "KExit.h"
namespace KapitanGame
{
void KPawn::CollisionDetectionStep(const std::vector<std::shared_ptr<KObject>>& objects)
{
if (GetCollider() == nullptr) return;
for (auto& other : objects) {
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;
}
}
}
void KPawn::MovementStep(const float& timeStep)
{
Position += Velocity * timeStep;
}
void KPawn::CollisionDetectionWithMapStep(const SDL_FRect& map)
{
Position += GetCollider()->GetSeparationVector(map);
}
void KPawn::AddMovementInput(const KVector2D& input)
{
Velocity = input * Constants::SPEED * (1 - Constants::SMOOTH) + Velocity * Constants::SMOOTH;
}
}

29
2dgk_7/2dgk_7/KPawn.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include <vector>
#include "KObject.h"
namespace KapitanGame
{
class KPlayerController;
class KPawn : public KObject
{
public:
KPawn(const KVector2D& position, const KTexture& texture,
const std::shared_ptr<KPlayerController>& playerController)
: KObject(position, texture),
PlayerController(playerController)
{
}
void CollisionDetectionStep(const std::vector<std::shared_ptr<KObject>>& objects);
void MovementStep(const float& timeStep);
void CollisionDetectionWithMapStep(const SDL_FRect& map);
void AddMovementInput(const KVector2D& input);
private:
const std::weak_ptr<KPlayerController> PlayerController;
KVector2D Velocity{ 0.f, 0.f };
};
}

View File

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

View File

@ -1,12 +1,13 @@
#include "KPlayerController.h"
#include "KGame.h"
#include "KInput.h"
namespace KapitanGame {
void KPlayerController::SetupInputBindings(KInput& input)
{
input.BindAxis("MoveYAxis", this, &KPlayerController::MoveYAxis, Player);
input.BindAxis("MoveXAxis", this, &KPlayerController::MoveXAxis, Player);
input.BindAxis("MoveY", shared_from_this(), &KPlayerController::MoveYAxis, Player);
input.BindAxis("MoveX", shared_from_this(), &KPlayerController::MoveXAxis, Player);
}
void KPlayerController::MoveYAxis(const float axis)
@ -21,7 +22,28 @@ namespace KapitanGame {
void KPlayerController::Update(float deltaTime)
{
Input.Normalize();
Pawn->AddMovementInput(Input);
Input = KVector2D(0.f, 0.f);
if (Pawn != nullptr)
Pawn->AddMovementInput(Input);
Input *= 0;
}
void KPlayerController::NotifyWin() const
{
Game->Win(Player);
}
void KPlayerController::Possess(KPawn* pawn)
{
Pawn = pawn;
}
void KPlayerController::UnPossess()
{
Pawn = nullptr;
}
const KPlayer& KPlayerController::GetPlayer() const
{
return Player;
}
}

View File

@ -1,16 +1,18 @@
#pragma once
#include "Controllers.h"
#include "KPawn.h"
#include "KPlayer.h"
#include "KShape.h"
#include "KVector2d.h"
namespace KapitanGame {
class KGame;
class KInput;
class KPlayerController
class KPlayerController : public std::enable_shared_from_this<KPlayerController>
{
public:
KPlayerController(const KPlayer player) : Input(0.f, 0.f), Player(player)
KPlayerController(const KPlayer player, KGame* const game)
: Player(player),
Game(game)
{
}
@ -18,10 +20,15 @@ namespace KapitanGame {
void MoveYAxis(float axis);
void MoveXAxis(float axis);
void Update(float deltaTime);
void NotifyWin() const;
void Possess(KPawn* pawn);
void UnPossess();
const KPlayer& GetPlayer() const;
private:
KVector2D Input;
KPlayer Player;
KShape* Pawn;
KVector2D Input{ 0.f, 0.f };
const KPlayer Player;
KPawn* Pawn{};
KGame* Game;
};
typedef void (KPlayerController::* KPlayerCommand)();
typedef void (KPlayerController::* KPlayerAxisCommand)(float input);

View File

@ -4,12 +4,6 @@
#include "Utils.h"
namespace KapitanGame {
KRect::KRect(const KVector2D& position, const KVector2D& velocity, const KTexture& texture, const float width,
const float height) : KShape(position, velocity, texture), Width(width), Height(height) {
}
void KRect::CollisionDetectionWithMapStep(const SDL_Rect& map) {
}
float KRect::GetWidth() const {
return Width;
@ -20,54 +14,121 @@ namespace KapitanGame {
}
KVector2D KRect::GetSeparationVector(const float left, const float right, const float top, const float bottom) {
auto x = left < right ? -left : right;
auto y = top < bottom ? -top : 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))
y = 0;
vY = 0;
if (fabs(x) > fabs(y))
x = 0;
return { x, y };
vX = 0;
return { vX, vY };
}
KVector2D KRect::GetSeparationVector(const KCircle& other) const {
const float l = Position.X - Width / 2;
const float r = Position.X + Width / 2;
const float t = Position.Y - Height / 2;
const float b = Position.Y + Height / 2;
const auto f = KVector2D(Utils::Clamp(other.GetPosition().X, l, r),
Utils::Clamp(other.GetPosition().Y, t, b));
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.GetPosition() == f) {
const auto left = other.GetPosition().X - l + other.GetRadius();
const auto right = r - other.GetPosition().X + other.GetRadius();
const auto top = other.GetPosition().Y - t + other.GetRadius();
const auto bottom = b - other.GetPosition().Y + other.GetRadius();
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.GetPosition() - f) / (other.GetPosition() - f).Length() * (other.GetRadius() - (other.GetPosition() - f).Length()) * 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 = Position.X + Width / 2 - (other.Position.X - other.Width / 2);
const auto right = other.Position.X + other.Width / 2 - (Position.X - Width / 2);
const auto top = Position.Y + Height / 2 - (other.Position.Y - other.Height / 2);
const auto bottom = other.Position.Y + other.Height / 2 - (Position.Y - Height / 2);
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.GetPosition().X, Position.X - Width / 2, Position.X + Width / 2),
Utils::Clamp(other.GetPosition().Y, Position.Y - Height / 2, Position.Y + Height / 2));
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 (Position - f).Length() < other.GetRadius();
return (other->GetParent()->GetPosition() - f).Length() < other->GetRadius();
}
bool KRect::IsCollision(const KRect& other) const {
return Position.X + Width / 2 > other.Position.X - other.Width / 2
&& other.Position.X + other.Width / 2 > Position.X - Width / 2
&& Position.Y + Height / 2 > other.Position.Y - other.Height / 2
&& other.Position.Y + other.Height / 2 > Position.Y - Height / 2;
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

@ -1,21 +1,35 @@
#pragma once
#include "KShape.h"
#include <SDL_rect.h>
#include "KCollider.h"
namespace KapitanGame {
class KRect final : public KShape
class KCircle;
class KRect final : public KCollider
{
public:
KRect(const KVector2D& position, const KVector2D& velocity, const KTexture& texture, float width, float height);
void CollisionDetectionWithMapStep(const SDL_Rect& map) override;
float GetWidth() const;
float GetHeight() const;
KRect(KObject* parent, const float width, const float height)
: KCollider(parent),
Width(width),
Height(height)
{
}
float GetWidth() const override;
float GetHeight() const override;
static KVector2D GetSeparationVector(float left, float right, float top, float bottom);
protected:
KVector2D GetSeparationVector(const KCircle& other) const override;
KVector2D GetSeparationVector(const KRect& other) const override;
bool IsCollision(const KCircle& other) const override;
bool IsCollision(const KRect& other) const override;
bool IsCollision(const KCollider* other) const override;
KVector2D GetSeparationVector(const KCollider* other) const override;
KVector2D GetSeparationVector(const SDL_FRect& map) const override;
private:
KVector2D GetSeparationVector(const KCircle* other) const;
KVector2D GetSeparationVector(const KRect* other) const;
bool IsCollision(const KCircle* other) const;
float GetLeft() const;
float GetRight() const;
float GetBottom() const;
float GetTop() const;
bool IsCollision(const KRect* other) const;
float Width;
float Height;
};

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) : KPawn(position, texture, playerController),
Collider(this, texture.GetWidth(), texture.GetHeight())
{
}
const KCollider* KRectPawn::GetCollider() const
{
return &Collider;
}
}

20
2dgk_7/2dgk_7/KRectPawn.h Normal file
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);
const KCollider* GetCollider() const override;
private:
KRect Collider;
};
}

View File

@ -1,85 +0,0 @@
#include "KShape.h"
#include "KCircle.h"
#include "KRect.h"
#include <stdexcept>
#include <typeinfo>
#include "Constants.h"
namespace KapitanGame {
std::atomic<int> KShape::IdCounter{ 0 };
KShape::KShape(const KVector2D& position, const KVector2D& velocity, const KTexture& texture) : Id(++IdCounter),
Position(position),
Velocity(velocity),
Texture(texture) {
}
KShape::~KShape() = default;
void KShape::CollisionDetectionStep(const std::vector<KShape>& shapes, const bool& shouldSeparate,
const bool& shouldReflect) {
for (auto& other : shapes) {
if (other.Id == Id) continue;
if (IsCollision(other)) {
auto separationVector = GetSeparationVector(other);
if (shouldSeparate)
Position += separationVector;
if (shouldReflect)
{
separationVector.Normalize();
Velocity = Velocity.Reflect(separationVector);
}
}
}
}
bool KShape::IsCollision(const KShape& other) const {
try {
auto& circle = dynamic_cast<const KCircle&>(other);
return IsCollision(circle);
}
catch (const std::bad_cast&) {
}
try {
auto& rect = dynamic_cast<const KRect&>(other);
return IsCollision(rect);
}
catch (const std::bad_cast&) {
}
throw std::runtime_error("unsupported shape");
}
KVector2D KShape::GetSeparationVector(const KShape& other) const {
try {
auto& circle = dynamic_cast<const KCircle&>(other);
return GetSeparationVector(circle);
}
catch (const std::bad_cast&) {
}
try {
auto& circle = dynamic_cast<const KRect&>(other);
return GetSeparationVector(circle);
}
catch (const std::bad_cast&) {
}
throw std::runtime_error("unsupported shape");
}
void KShape::MovementStep(const float& timeStep) {
Position += Velocity * timeStep;
}
void KShape::Render(SDL_Renderer* renderer) const {
Texture.Render(renderer, static_cast<int>(Position.X) - Texture.GetWidth() / 2, static_cast<int>(Position.Y) - Texture.GetHeight() / 2);
}
KVector2D KShape::GetPosition() const {
return Position;
}
void KShape::AddMovementInput(const KVector2D& input) {
Velocity = input * Constants::SPEED * (1 - Constants::SMOOTH) + Velocity * Constants::SMOOTH;
}
}

View File

@ -1,45 +0,0 @@
#pragma once
#include <atomic>
#include <SDL_render.h>
#include <vector>
#include "KTexture.h"
#include "KVector2d.h"
namespace KapitanGame {
class KRect;
class KCircle;
class KShape
{
public:
KShape(const KVector2D& position, const KVector2D& velocity, const KTexture& texture);
virtual ~KShape();
KShape() = delete;
KShape(const KShape& other) = default;
KShape(KShape&& other) = default;
KShape& operator=(KShape&& other) = delete;
KShape& operator=(const KShape& other) = delete;
void CollisionDetectionStep(const std::vector<KShape>& shapes, const bool& shouldSeparate, const bool& shouldReflect);
void MovementStep(const float& timeStep);
bool IsCollision(const KShape& other) const;
KVector2D GetSeparationVector(const KShape& other) const;
void Render(SDL_Renderer* renderer) const;
virtual void CollisionDetectionWithMapStep(const SDL_Rect& map) = 0;
KVector2D GetPosition() const;
void AddMovementInput(const KVector2D& input);
const int Id;
static std::atomic<int> IdCounter;
protected:
KVector2D Position{ 0.f, 0.f };
KVector2D Velocity{ 0.f, 0.f };
virtual KVector2D GetSeparationVector(const KCircle& other) const = 0;
virtual KVector2D GetSeparationVector(const KRect& other) const = 0;
virtual bool IsCollision(const KCircle& other) const = 0;
virtual bool IsCollision(const KRect& other) const = 0;
private:
const KTexture& Texture;
};
}

View File

@ -1,27 +1,17 @@
#include "KTexture.h"
namespace KapitanGame {
KTexture::KTexture()
KTexture::KTexture() : Texture(nullptr), Width(0), Height(0)
{
//Initialize
Texture = nullptr;
Width = 0;
Height = 0;
}
KTexture::KTexture(KTexture&& other) noexcept
: Texture(other.Texture),
Width(other.Width),
Height(other.Height) {
}
KTexture& KTexture::operator=(const KTexture& other) {
if (this == &other)
return *this;
Texture = other.Texture;
Width = other.Width;
Height = other.Height;
return *this;
other.Texture = nullptr;
other.Width = 0;
other.Height = 0;
}
KTexture& KTexture::operator=(KTexture&& other) noexcept {
@ -30,6 +20,9 @@ namespace KapitanGame {
Texture = other.Texture;
Width = other.Width;
Height = other.Height;
other.Texture = nullptr;
other.Width = 0;
other.Height = 0;
return *this;
}
@ -78,6 +71,22 @@ namespace KapitanGame {
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
@ -90,12 +99,13 @@ namespace KapitanGame {
}
}
void KTexture::Render(SDL_Renderer* renderer, const int x, const int y, SDL_Rect* clip, const float scale) const
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_Rect renderQuad = {
static_cast<int>(static_cast<float>(x) * scale), static_cast<int>(static_cast<float>(y) * scale),
static_cast<int>(static_cast<float>(Width) * scale), static_cast<int>(static_cast<float>(Height) * scale)
SDL_FRect renderQuad = {
x * scale, y * scale,
Width * scale, Height * scale
};
//Set clip rendering dimensions
@ -106,7 +116,20 @@ namespace KapitanGame {
}
//Render to screen
SDL_RenderCopy(renderer, Texture, clip, &renderQuad);
SDL_RenderCopyF(renderer, Texture, clip, &renderQuad);
}
void KTexture::RenderEx(SDL_Renderer* renderer, const float x, const float y, const double degrees) const
{
if (Texture == nullptr) return;
//Set rendering space and render to screen
const SDL_FRect renderQuad = {
x , y ,
static_cast<float>(Width) , static_cast<float>(Height)
};
//Render to screen
SDL_RenderCopyExF(renderer, Texture, nullptr, &renderQuad, degrees, nullptr, SDL_FLIP_NONE);
}
int KTexture::GetWidth() const

View File

@ -9,23 +9,28 @@ namespace KapitanGame {
KTexture();
~KTexture();
KTexture(const KTexture& other) = default;
KTexture(const KTexture& other) = delete;
KTexture(KTexture&& other) noexcept;
KTexture& operator=(const KTexture& other);
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, int x, int y, SDL_Rect* clip = nullptr, float scale = 1.f) const;
void Render(SDL_Renderer* renderer, float x, float y, SDL_Rect* clip = nullptr, float scale = 1.f) const;
void RenderEx(SDL_Renderer* renderer, float x, float y, double degrees) const;
//Gets image dimensions
int GetWidth() const;

View File

@ -1,4 +1,6 @@
#pragma once
#include <cfloat>
#define _USE_MATH_DEFINES
#include <cmath>
namespace KapitanGame {

9
2dgk_7/2dgk_7/KWall.cpp Normal file
View File

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

22
2dgk_7/2dgk_7/KWall.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "KObject.h"
#include "KRect.h"
namespace KapitanGame
{
class KWall final :
public KObject
{
public:
KWall(const KVector2D& position, const KTexture& texture)
: KObject(position, texture),
Collider(this, texture.GetWidth() * 1.f, texture.GetHeight() * 1.f)
{
}
const KCollider* GetCollider() const override;
private:
KRect Collider;
};
}

View File

@ -1,16 +1,7 @@
#include "Utils.h"
#include <random>
namespace KapitanGame {
namespace Utils {
double RandomNumber() {
// 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());
std::uniform_real_distribution<double> dist(0.0, 1.0);
return dist(rng);
}
}
}

View File

@ -3,7 +3,10 @@
#include <string>
#include <stdexcept>
#include <random>
#include <unordered_map>
#include "KPlayer.h"
namespace KapitanGame {
namespace Utils {
@ -18,19 +21,19 @@ namespace KapitanGame {
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
template <class T>
constexpr const T& Clamp01(const T& x)
{
return Clamp(x, 0.f, 1.f);
}
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) * t;
return a + (b - a) * Clamp01(t);
}
static std::default_random_engine make_default_random_engine()
@ -49,15 +52,49 @@ namespace KapitanGame {
return std::default_random_engine{ seq };
}
double RandomNumber();
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;
}
const KPlayer GetPlayerFromString(const std::string& str) {
static std::unordered_map<std::string, KPlayer> const table = { {"Player1",KPlayer::Player1},{"Player2",KPlayer::Player2} };
auto it = table.find(str);
if (it != table.end()) {
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::Player2> KPlayerIterator;
}
}
}

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.

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

Binary file not shown.

View File

@ -24,7 +24,7 @@
# # # # # # #
# # ### ##### ############# ### #####
# # # # # # # # # #
### # # ######### # # # # ### # ### #
### # # ######### # # # # # # # ### #
# # # # # # # # # #
# ##### ### ### # # ### # ### ##### #
# # # # # # # # # # # #

BIN
2dgk_7/2dgk_7/assets/textures/P1.bmp (Stored with Git LFS)

Binary file not shown.

BIN
2dgk_7/2dgk_7/assets/textures/P2.bmp (Stored with Git LFS)

Binary file not shown.

BIN
2dgk_7/2dgk_7/assets/textures/arrow.bmp (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,15 +0,0 @@
[Input]
[.Player1]
AxisMappings=(AxisName="MoveY",Scale=-1.000000,Key=W)
AxisMappings=(AxisName="MoveY",Scale=1.000000,Key=S)
AxisMappings=(AxisName="MoveX",Scale=1.000000,Key=Gamepad1_LeftX)
AxisMappings=(AxisName="MoveX",Scale=1.000000,Key=D)
AxisMappings=(AxisName="MoveX",Scale=-1.000000,Key=A)
AxisMappings=(AxisName="MoveY",Scale=1.000000,Key=Gamepad1_LeftY)
[.Player2]
AxisMappings=(AxisName="MoveY",Scale=-1.000000,Key=I)
AxisMappings=(AxisName="MoveY",Scale=1.000000,Key=K)
AxisMappings=(AxisName="MoveX",Scale=1.000000,Key=L)
AxisMappings=(AxisName="MoveX",Scale=-1.000000,Key=J)
AxisMappings=(AxisName="MoveY",Scale=1.000000,Key=Gamepad2_LeftY)
AxisMappings=(AxisName="MoveX",Scale=1.000000,Key=Gamepad2_LeftX)

View File

@ -24,13 +24,13 @@
},
{
"AxisName": "MoveY",
"Scale": -1.000000,
"Key": "Gamepad1_LeftY"
"Scale": 1.000000,
"Key": "Gamepad0_LeftY"
},
{
"AxisName": "MoveX",
"Scale": 1.000000,
"Key": "Gamepad1_LeftX"
"Key": "Gamepad0_LeftX"
}
],
"ActionMappings": []
@ -49,23 +49,23 @@
},
{
"AxisName": "MoveX",
"Scale": 1.000000,
"Scale": -1.000000,
"Key": "J"
},
{
"AxisName": "MoveX",
"Scale": -1.000000,
"Scale": 1.000000,
"Key": "L"
},
{
"AxisName": "MoveY",
"Scale": -1.000000,
"Key": "Gamepad2_LeftY"
"Scale": 1.000000,
"Key": "Gamepad1_LeftY"
},
{
"AxisName": "MoveX",
"Scale": 1.000000,
"Key": "Gamepad2_LeftX"
"Key": "Gamepad1_LeftX"
}
],
"ActionMappings": []

View File

@ -1,31 +0,0 @@
/------------\/------------\
|............||............|
|./--\./---\.||./---\./--\.|
|#| |.| |.||.| |.| |#|
|.`--'.`---'.`'.`---'.`--'.|
|..........................|
|./--\./\./------\./\./--\.|
|.`--'.||.`--\/--'.||.`--'.|
|......||....||....||......|
`----\.|`--\ || /--'|./----'
|.|/--' `' `--\|.|
|.|| ||.|
|.|| /--==--\ ||.|
-----'.`' | | `'.`-----
. | | .
-----\./\ | | /\./-----
|.|| `------' ||.|
|.|| ||.|
|.|| /------\ ||.|
/----'.`' `--\/--' `'.`----\
|............||............|
|./--\./---\.||./---\./--\.|
|.`-\|.`---'.`'.`---'.|/-'.|
|#..||....... .......||..#|
`-\.||./\./------\./\.||./-'
/-'.`'.||.`--\/--'.||.`'.`-\
|......||....||....||......|
|./----'`--\.||./--'`----\.|
|.`--------'.`'.`--------'.|
|..........................|
`--------------------------'

14
2dgk_7/2dgk_7/resource.h Normal file
View File

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

@ -4,6 +4,7 @@
"version": "0.1.0",
"dependencies": [
"sdl2",
"nlohmann-json"
"nlohmann-json",
"sdl2-ttf"
]
}