Files
2dkg/2dgk_zad3/2dgk_zad3/KGame.cpp
2021-12-16 14:30:32 +01:00

363 lines
11 KiB
C++

#include "KGame.h"
#include "SDL.h"
#include <SDL_ttf.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 "KExit.h"
#include "KRectPawn.h"
#include "KTexture.h"
#include "KTile.h"
#include "KVector2d.h"
#include "KWall.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace KapitanGame {
KGame::KGame() : Time(0), PreviousTime(0), Map()
{
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
throw std::runtime_error(Utils::StringFormat("SDL could not initialize! SDL_Error: %s", SDL_GetError()));
}
//Set texture filtering to linear
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf("Warning: Linear texture filtering not enabled!\n");
}
Input.Init();
if (TTF_Init() < 0)
{
throw std::runtime_error(Utils::StringFormat("SDL_TTF could not initialize! TTF_Error: %s", TTF_GetError()));
}
//Create window
Window = SDL_CreateWindow(Constants::WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (Window == nullptr)
{
throw std::runtime_error(Utils::StringFormat("Window could not be created! SDL_Error: %s", SDL_GetError()));
}
//Create renderer for window
Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_ACCELERATED);
if (Renderer == nullptr)
{
throw std::runtime_error(
Utils::StringFormat("Renderer could not be created! SDL Error: %s", SDL_GetError()));
}
//Initialize renderer color
SDL_SetRenderDrawColor(Renderer, 0, 0xFF, 0, 0xFF);
}
KGame::~KGame() {
//Free loaded images
Textures.clear();
Objects.clear();
Pawns.clear();
PlayerControllers.clear();
Fonts.clear();
TTF_Quit();
Input.Free();
//Destroy window
SDL_DestroyRenderer(Renderer);
SDL_DestroyWindow(Window);
Window = nullptr;
Renderer = nullptr;
//Quit SDL subsystems
SDL_Quit();
}
bool KGame::LoadLevel()
{
bool success = true;
Objects.clear();
FreePositions.clear();
/*std::ifstream levelFile;
levelFile.open("assets/levels/level" + std::to_string(LvlCounter) + ".txt");
if (levelFile.fail())
{
printf("Failed to load assets/levels/level%d.txt!\n", LvlCounter);
success = false;
}
else
{
int y = 0;
float mapWidth = 0;
std::string line;
while (std::getline(levelFile, line)) {
if (mapWidth < static_cast<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(std::make_pair(static_cast<int>(i), y), 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 };
}*/
Map = { 0,0,Constants::SCREEN_WIDTH,Constants::SCREEN_HEIGHT };
return success;
}
void KGame::LoadPlayerPawn()
{
Pawns.clear();
KVector2D StartPosition{ 0.f, 0.f };
Pawns.emplace_back(std::make_shared<KCirclePawn>(StartPosition, Textures["P1.bmp"], PlayerControllers[static_cast<int>(KPlayer::Player1)]));
PlayerControllers[static_cast<int>(KPlayer::Player1)]->Possess(Pawns.back().get());
}
bool KGame::LoadMedia()
{
//Loading success flag
bool success = true;
for (auto player : Utils::KPlayerIterator())
{
std::string filename = "P" + std::to_string(static_cast<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);
}
Textures.emplace("wall.bmp", KTexture());
if (!Textures["wall.bmp"].LoadFromFile("assets/textures/wall.bmp", Renderer))
{
printf("Failed to load wall texture image!\n");
Textures.erase("wall.bmp");
success = false;
}
Fonts.emplace("PressStart2P-Regular", KFont());
if (!Fonts["PressStart2P-Regular"].LoadFromFile("assets/fonts/PressStart2P-Regular.ttf", 72))
{
printf("Failed to load PressStart2P-Regular font!\n");
Fonts.erase("PressStart2P-Regular");
success = false;
}
//Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextWithOutlineTexture("0:0", { 0xFF,0xFF,0xFF,0xFF }, { 0,0,0,0xFF }, 1, Renderer));
//Textures.emplace("Text_Winner", KTexture());
std::ifstream configFile("config.json");
if (configFile.fail()) {
printf("Failed to load config.json!\n");
success = false;
}
else {
nlohmann::json configJson;
configFile >> configJson;
configFile.close();
for (auto& player : configJson["Input"].items()) {
const auto playerEnum = Utils::GetPlayerFromString(player.key());
for (auto& axisMapping : player.value()["AxisMappings"]) {
Input.AddAxisMapping(axisMapping["AxisName"].get<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);
bool debug = false;
LoadPlayerPawn();
camera.Update(Pawns, Map);
Time = PreviousTime = SDL_GetTicks();
printf("\n");
//While application is running
while (!quit)
{
PreviousTime = Time;
Time = SDL_GetTicks();
float deltaTime = (Time - PreviousTime) * 0.001f;
Input.HandleInputPreEvents();
//Handle events on queue
while (SDL_PollEvent(&e))
{
//User requests quit
if (e.type == SDL_QUIT)
{
quit = true;
continue;
}
Input.HandleEvent(e);
}
Input.HandleInputPostEvents(Playing);
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F1))
{
debug = !debug;
}
if (Input.IsKeyboardButtonPressed(SDL_SCANCODE_F2))
{
CollisionEnabled = !CollisionEnabled;
}
if (Playing) {
for (const auto& pc : PlayerControllers) {
pc->Update(deltaTime);
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->MovementStep(deltaTime);
}
if (CollisionEnabled) {
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionStep(Objects);
}
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionWithMapStep(Map);
}
for (const auto& pawn : Pawns) {
if (!Playing) break;
pawn->CollisionDetectionWithMapStep(camera.GetPlayArea());
}
camera.Update(Pawns, Map);
}
if (!Playing)
{
if (Time > RestartTick)
{
LoadLevel();
LoadPlayerPawn();
debugCamera.SetDebug(Map);
camera.Update(Pawns, Map);
if (ShowWinner)
{
for (auto i : Utils::KPlayerIterator())
{
Scores[static_cast<int>(i)] = 0;
}
//Textures.erase("Text_Score");
//Textures.emplace("Text_Score", Fonts["Roboto-Thin"].GetTextWithOutlineTexture(Utils::StringFormat("%d:%d", Scores[0], Scores[1]), { 0xFF,0xFF,0xFF,0xFF }, { 0,0,0,0xFF }, 1, Renderer));
ShowWinner = false;
}
Playing = true;
continue;
}
}
//Clear screen
SDL_SetRenderDrawColor(Renderer, 66, 135, 245, 0xFF);
SDL_RenderClear(Renderer);
const auto& cameraInUse = debug ? debugCamera : camera;
if (Playing) {
for (const auto& object : Objects)
object.second->Render(Renderer, cameraInUse);
for (const auto& pawn : Pawns) {
pawn->Render(Renderer, cameraInUse);
}
if (const auto exit = Exit.lock()) {
const float exitX = camera.GetViewport().x + Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f - exit->GetPosition().X + exit->GetCollider()->GetWidth() / 2.f;
const float exitY = camera.GetViewport().y + 25.f - exit->GetPosition().Y + exit->GetCollider()->GetHeight() / 2.f;
const double degrees = atan2(-exitX, exitY) * (180.f / M_PI);
Textures["arrow.bmp"].RenderEx(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["arrow.bmp"].GetWidth() / 2.f, 25.f, degrees);
}
}
if (ShowWinner)
{
Textures["Text_Winner"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Winner"].GetWidth() / 2.f, 25.f);
}
Textures["Text_Score"].Render(Renderer, Constants::SCREEN_WIDTH / 2.f - Textures["Text_Score"].GetWidth() / 2.f, Constants::SCREEN_HEIGHT - 10.f - Textures["Text_Score"].GetHeight());
if (debug)
{
SDL_SetRenderDrawColor(Renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderDrawLineF(Renderer, 0, Constants::SCREEN_HEIGHT / 2.f, Constants::SCREEN_WIDTH, Constants::SCREEN_HEIGHT / 2.f);
SDL_RenderDrawLineF(Renderer, Constants::SCREEN_WIDTH / 2.f, 0, Constants::SCREEN_WIDTH / 2.f, Constants::SCREEN_HEIGHT);
SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderDrawPointF(Renderer, camera.GetFocusPoint().X * debugCamera.GetScale(), camera.GetFocusPoint().Y * debugCamera.GetScale());
SDL_SetRenderDrawColor(Renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_FRect debugViewport = { camera.GetViewport().x * debugCamera.GetScale(),
camera.GetViewport().y * debugCamera.GetScale(),
camera.GetViewport().w * debugCamera.GetScale(),
camera.GetViewport().h * debugCamera.GetScale() };
SDL_RenderDrawRectF(Renderer, &debugViewport);
SDL_FRect debug2Viewport = { camera.GetPlayArea().x * debugCamera.GetScale(),
camera.GetPlayArea().y * debugCamera.GetScale(),
camera.GetPlayArea().w * debugCamera.GetScale(),
camera.GetPlayArea().h * debugCamera.GetScale() };
SDL_SetRenderDrawColor(Renderer, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderDrawRectF(Renderer, &debug2Viewport);
}
//Update screen
SDL_RenderPresent(Renderer);
}
}
return 0;
}
}