From 61522bbf1631f4fc80e46ed6f4424c4a263f4e31 Mon Sep 17 00:00:00 2001 From: Stan_Lewry Date: Fri, 30 Aug 2024 18:43:09 +0100 Subject: [PATCH] fix line endings --- combat.cpp | 1462 ++++++++++++++++++++++++------------------------- combat.h | 8 +- globals.cpp | 82 +-- globals.h | 112 ++-- main.cpp | 456 +++++++-------- main_menu.cpp | 130 ++--- main_menu.h | 6 +- tilemap.cpp | 164 +++--- tilemap.h | 34 +- ui.cpp | 180 +++--- ui.h | 12 +- 11 files changed, 1323 insertions(+), 1323 deletions(-) diff --git a/combat.cpp b/combat.cpp index 755988d..a69026f 100644 --- a/combat.cpp +++ b/combat.cpp @@ -1,732 +1,732 @@ -#define _CRT_SECURE_NO_WARNINGS - -#include "combat.h" -#include "globals.h" -#include "ui.h" -#include "tilemap.h" - -#include -#include - - -struct Character { - bool allied; - std::string name; - int currentHP; - int maxHP; - int currentMP; - int maxMP; - int attack; - float agility; // to determine move order - float moveDist; - - // animation stuff? - SDL_Texture* texture; - S2DE::Vec2 position; - // direction vector? - // how to handle "moves" - S2DE::Vec2 combatMoveDestination = { 0.0f, 0.0f }; - - int basicAttackRange = 1.0f; - - bool canMove = true; - bool canAttack = true; - - bool alive = true; -}; - -std::vector combatants; -int currentCombatantIndex = -1; -Character* activeCombatant; - -std::vector targets; -int currentTargetIdx = 0; - -enum CombatState { - TURN_ORDER, - ACTION_SELECT, - PLAYER_MOVE, - SELECT_TARGET, - DO_ATTACK, - ENEMY_MOVE, - MOVE_TO_POSITION, -}; - -CombatState currentCombatState = TURN_ORDER; - -enum Spell { - BASIC_ATTACK -}; - -Spell currentSpell = BASIC_ATTACK; - -static double frameTimer = 0; -static const double frameTime = 1.0f / 60.0f; - -//bool playerTurn = true; - -SDL_Texture* arrowSprite = nullptr; -SDL_Texture* indicatorSprite = nullptr; -SDL_Texture* indicatorRedSprite = nullptr; - -static constexpr int arenaWidth = 100; -static constexpr int arenaHeight = 100; -WorldCell** arena; -WorldCell** fogLayer; -S2DE::Camera combatCam = { 23.5, 11.5 }; - -S2DE::Vec2 moveCursorPos; -S2DE::Vec2 arenaCenter = { 23, 11 }; - -//S2DE::Vec2* currentMoveDest = &moveCursorPos; - -static const int numActions = 4; -static const char* actions[numActions] = {"Move", "Attack", "End", "FLEE"}; -int currentAction = 0; - -SDL_Colour hpColour = { 136, 8, 8, 255 }; -SDL_Colour mpColour = { 0, 150, 255, 255 }; - -void renderCombat(); - -void renderUIFull(); -void renderActionsPanel(); -void renderCombatants(); -void renderStatsPanel(); - -// lerp functions -float interpolatePosition(S2DE::Vec2* entityPos, S2DE::Vec2 destination, float t, float speed); -void moveToPosition(Character* c, S2DE::Vec2 destination, float speed); - -void runStateFunction(CombatState state, double delta); -void actionSelectState(double delta); -void playerMoveActionState(double delta); -void enemyMoveActionState(double delta); -void movingCharacterState(double delta); -void determineNextTurnState(double delta); -void selectAttackTarget(double delta); -void doAttack(double delta); // plays attack animation, resolves and applies damage. - -void runStateFunction(CombatState state, double delta) { - switch (state) { - case TURN_ORDER: determineNextTurnState(delta); break; - case ACTION_SELECT: actionSelectState(delta); break; - case PLAYER_MOVE: playerMoveActionState(delta); break; - case SELECT_TARGET: selectAttackTarget(delta); break; - case ENEMY_MOVE: enemyMoveActionState(delta); break; - case MOVE_TO_POSITION: movingCharacterState(delta); break; - case DO_ATTACK: doAttack(delta); break; - default: assert(false); break; - } -} - -float distance(S2DE::Vec2 p1, S2DE::Vec2 p2) { - return std::sqrt(std::pow(p2.x - p1.x, 2) + std::powf(p2.y - p1.y, 2)); -} - -void renderMeter(int x, int y, int width, int height, float percentage, SDL_Colour fillColour, int style) { - if (style == 1) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 180); - SDL_Rect bgRect = { x, y, width, height }; - SDL_RenderFillRect(renderer, &bgRect); - } - else if (style == 2) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderDrawLine(renderer, x, y, x + width, y); - SDL_RenderDrawLine(renderer, x, y + height, x + width, y + height); - - SDL_RenderDrawLine(renderer, x, y, x, y + height); - SDL_RenderDrawLine(renderer, x + width, y, x + width, y + height); - } - - SDL_SetRenderDrawColor(renderer, fillColour.r, fillColour.g, fillColour.b, fillColour.a); - int panelWidth = width * percentage; - SDL_Rect fillRect = { x+1, y+1, panelWidth -1, height-1 }; - SDL_RenderFillRect(renderer, &fillRect); -} - -void renderStatsPanel() { - int panelWidth = 300; - int panelHeight = 200; - int outerPad = 2; - int innerPad = 16; - - int panelX = WINDOW_WIDTH - panelWidth - outerPad; - int panelY = WINDOW_HEIGHT - panelHeight - outerPad; - - renderBasicPanel(panelX, panelY, panelWidth, panelHeight); - renderString(panelX + innerPad, panelY + innerPad, activeCombatant->name.c_str()); - - int portraitWidth = 80; - int portraitHeight = 80; - - int portraitX = panelX + 16; - int portraitY = panelY + 50; - renderBasicPanel(portraitX, portraitY, portraitWidth, portraitHeight); - SDL_Rect characterDRect = { portraitX + 8, portraitY + 8, portraitWidth - 16, portraitHeight - 16}; - SDL_Rect characterSRect = { 0 , 0, 32, 32 }; - SDL_Texture* portraitTexture = activeCombatant->texture; - S2DE::renderTexture(&renderer, &portraitTexture, &characterSRect, &characterDRect); - - - renderString(portraitX + portraitWidth + innerPad, portraitY, "HP:"); - int valPad = 100; - char hpStr[10]; - sprintf(hpStr, "%d/%d", activeCombatant->currentHP, activeCombatant->maxHP); - renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, hpStr); - - float hpLvl = (float)activeCombatant->currentHP / (float)activeCombatant->maxHP; - renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, hpLvl, hpColour, 2); - - renderString(portraitX + portraitWidth + innerPad, portraitY + innerPad + 22, "MP:"); - - char mpStr[10]; - sprintf(mpStr, "%d/%d", activeCombatant->currentMP, activeCombatant->maxMP); - renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, mpStr); - - float mpLvl = (float)activeCombatant->currentMP / (float)activeCombatant->maxMP; - renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, mpLvl, mpColour, 2); - -} - -void renderActionsPanel() { - int panelWidth = 150; - int panelHeight = 150; - - //int panelX = WINDOW_WIDTH / 2 - panelWidth / 2; - int panelX = 100; - int panelY = WINDOW_HEIGHT - panelHeight - 2; - - renderBasicPanel(panelX, panelY, panelWidth, panelHeight); - - int leftPad = 40; - int topPad = 20; - int itemSpacing = 30; - - for (int i = 0; i < numActions; ++i) { - // a bit of a brittle way of doing this - if (i == 0 && !activeCombatant->canMove) { - renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey); - } - else if (i == 1 && !activeCombatant->canAttack) { - renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey); - } - else { - renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i]); - } - } - - renderString(panelX + 20, panelY + topPad + (itemSpacing * currentAction), ">"); -} - -void renderUIFull() { - renderActionsPanel(); - renderStatsPanel(); -} - -void renderCombat() { - renderTilemap(arena, arenaWidth, arenaHeight, combatCam); - renderCombatants(); - renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // render the fog layer -} - -void renderCombatants() { - - for (Character c : combatants) { - - if (c.alive) { - S2DE::Vec2 pos = c.position; - S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - S2DE::Rect charSRect = { 0, 0, 32, 32 }; - - // disabled for now - //if (c.allied) { - // // do the looking logic only for allied characters - // int playerFrame = 1; - // int playerDir = 0; - - // Character enemy = combatants.at(1); - - // int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5); - // int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5); - - // if (abs(lookDeltaX) > abs(lookDeltaY)) { - // if (lookDeltaX > 0) playerDir = 2; - // else playerDir = 6; - // } - // else { - // if (lookDeltaY > 0) playerDir = 4; - // else playerDir = 0; - // } - - // charSRect = { playerFrame * 32, playerDir * 32, 32, 32 }; - //} - - SDL_Texture* texture = c.texture; - S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect); - - float hpLvl = (float)c.currentHP / (float)c.maxHP; - renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, hpLvl, hpColour, 1); - } - } - - // render the little arrow - S2DE::Vec2 arrowPos = activeCombatant->position; - - arrowPos.y -= 0.7; - S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - S2DE::renderTexture(&renderer, &indicatorSprite, NULL, &arrowDRect); -} - -void initCombatScene() -{ - // I think all resources should be initialized and cleaned up in the globals tbh - arena = new WorldCell * [arenaHeight]; - for (int i = 0; i < arenaHeight; ++i) arena[i] = new WorldCell[arenaWidth]; - - fogLayer = new WorldCell * [arenaHeight]; - for (int i = 0; i < arenaHeight; ++i) fogLayer[i] = new WorldCell[arenaWidth]; - - loadWorld("maps/combat_arena_1.tmj", arena, arenaWidth, arenaHeight); - loadWorld("maps/combat_arena_1_fog.tmj", fogLayer, arenaWidth, arenaHeight); - - arrowSprite = S2DE::loadTexture("assets/arrow.png", &renderer); - indicatorSprite = S2DE::loadTexture("assets/little_indicator.png", &renderer); - indicatorRedSprite = S2DE::loadTexture("assets/little_indicator_red.png", &renderer); - - //Character player = { true, "Player", 100, 100, 50, 50, 10.0f, 3.0f, player_sheet, { 23.0f, 13.0f } }; - Character player; - player.allied = true; - player.name = "Player"; - player.maxHP = 100; - player.currentHP = player.maxHP; - player.maxMP = 50; - player.currentMP = player.maxMP; - player.agility = 10.0f; - player.moveDist = 3.0f; - player.texture = player_forward_texture; - player.position = { arenaCenter.x, arenaCenter.y + 2 }; - player.attack = 5; - - - Character monica; - monica.allied = true; - monica.name = "Monica"; - monica.maxHP = 100; - monica.currentHP = monica.maxHP; - monica.maxMP = 50; - monica.currentMP = monica.maxMP; - monica.agility = 8.0f; - monica.moveDist = 6.0f; - monica.texture = monica_texture; - monica.position = { player.position.x - 2, player.position.y }; - monica.attack = 6; - - Character enemy; - enemy.allied = false; - enemy.name = "Bird"; - enemy.maxHP = 25; - enemy.currentHP = enemy.maxHP; - enemy.maxMP = 10; - enemy.currentMP = enemy.maxMP; - enemy.agility = 5.0f; - enemy.moveDist = 1.5f; - enemy.texture = bird; - enemy.position = { arenaCenter.x, arenaCenter.y - 2 }; - enemy.attack = 2; - - Character frog; - frog.allied = false; - frog.name = "Frog"; - frog.currentHP = frog.maxHP = 10; - frog.currentMP = frog.maxMP = 10; - frog.agility = 2; - frog.moveDist = 2.0f; - frog.texture = frog_texture; - frog.position = { arenaCenter.x - 1, arenaCenter.y - 2 }; - frog.attack = 2; - - combatants.push_back(player); - combatants.push_back(monica); - combatants.push_back(enemy); - combatants.push_back(frog); - - - // calculates turn order. Can expand the lambda to support other things - std::sort(combatants.begin(), combatants.end(), [](const Character& a, const Character& b) {return a.agility > b.agility; }); - - activeCombatant = &combatants.at(0); - moveCursorPos = activeCombatant->position; -} - - -void interpolatePosition(S2DE::Vec2* entityPos, S2DE::Vec2 destination, float* t, float speed) { - *t += speed; - - entityPos->x = (1.0f - *t) * entityPos->x + *t * destination.x; - entityPos->y = (1.0f - *t) * entityPos->y + *t * destination.y; -} - -void moveToPosition(Character* c, S2DE::Vec2 destination, float speed) { - float dist = distance(c->position, destination); - - S2DE::Vec2 direction {destination.x - c->position.x, destination.y - c->position.y}; - - direction.x /= dist; - direction.y /= dist; - - if (dist <= speed) { - c->position.x = destination.x; - c->position.y = destination.y; - } - else { - c->position.x += direction.x * speed; - c->position.y += direction.y * speed; - } -} - -void actionSelectState(double delta) { - S2DE::updateInputState(&inputState); - - // handle inputs - if (inputState.up) { - inputState.up = false; - currentAction--; - if (currentAction < 0) currentAction = numActions - 1; - } - else if (inputState.down) { - inputState.down = false; - currentAction++; - if (currentAction > numActions - 1) currentAction = 0; - } - else if (inputState.rtrn) { - inputState.rtrn = false; - switch (currentAction) { - case 0: - if (activeCombatant->canMove) { - currentCombatState = PLAYER_MOVE; - moveCursorPos = activeCombatant->position; - } - break; - case 1: // attack selected - if (activeCombatant->canAttack) { - // filter the targets - Have to do it here too in case the player attacks without moving? - targets.clear(); - for (auto& c : combatants) { - if (!c.allied && c.alive) { - float dist = distance(activeCombatant->position, c.position); - if (dist <= activeCombatant->basicAttackRange) { - targets.push_back(&c); - } - } - } - - currentCombatState = SELECT_TARGET; - } - break; - case 2: // end selected - currentCombatState = TURN_ORDER; - break; - - default: - inputState.quit = true; - break; - } - } - - SDL_RenderClear(renderer); - renderCombat(); - renderUIFull(); - SDL_RenderPresent(renderer); -} - -void playerMoveActionState(double delta) { - S2DE::updateInputState(&inputState); - - frameTimer += delta; - - Character player = *activeCombatant; - - if (frameTimer > frameTime) { - - frameTimer = 0; - - float cursorSpeed = 0.05; - - S2DE::Vec2 newCursorPos = moveCursorPos; - - float newY = moveCursorPos.y; - float newX = moveCursorPos.x; - - if (inputState.right) { - newX += cursorSpeed; - } - if (inputState.left) { - newX -= cursorSpeed; - } - if (inputState.up) { - newY -= cursorSpeed; - } - if (inputState.down) { - newY += cursorSpeed; - } - - if (inputState.rtrn) { - inputState.rtrn = false; - - activeCombatant->combatMoveDestination = moveCursorPos; - currentCombatState = MOVE_TO_POSITION; - } - - if (distance({ moveCursorPos.x, newY }, player.position) <= player.moveDist - && checkCollisionPoint({ moveCursorPos.x + 0.5f, newY + 0.5f }, arena) == false) { - moveCursorPos.y = newY; - } - if (distance({ newX, moveCursorPos.y }, player.position) <= player.moveDist - && checkCollisionPoint({ newX + 0.5f, moveCursorPos.y + 0.5f }, arena) == false) { - moveCursorPos.x = newX; - } - - } - - - // compute characters in melee range - targets.clear(); - for (auto& c : combatants) { - if (!c.allied && c.alive) { - float dist = distance(moveCursorPos, c.position); - if (dist <= activeCombatant->basicAttackRange) { - targets.push_back(&c); - } - } - } - - - SDL_RenderClear(renderer); - - renderTilemap(arena, arenaWidth, arenaHeight, combatCam); - - - S2DE::Vec2 playerCenterWorld = { player.position.x + 0.5, player.position.y + 0.5 }; - S2DE::Vec2 playerCenterScreen = S2DE::worldToScreenPoint(&combatCam, &playerCenterWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT); - - S2DE::renderCircle(&renderer, playerCenterScreen, (player.moveDist) * 64, { 0, 255, 255, 125 }); - - - S2DE::Vec2 lineEndWorld = { moveCursorPos.x + 0.5, moveCursorPos.y + 0.5 }; - S2DE::Vec2 lineEndPos = S2DE::worldToScreenPoint(&combatCam, &lineEndWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT); - - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - SDL_RenderDrawLine(renderer, playerCenterScreen.x, playerCenterScreen.y, lineEndPos.x, lineEndPos.y); - - // render lines to targets in range - SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); - for (auto t : targets) { - S2DE::Vec2 targetCenter = { t->position.x + 0.5, t->position.y + 0.5 }; - S2DE::Vec2 targetCenterScreen = S2DE::worldToScreenPoint(&combatCam, &targetCenter, 64, WINDOW_WIDTH, WINDOW_HEIGHT); - SDL_RenderDrawLine(renderer, lineEndPos.x, lineEndPos.y, targetCenterScreen.x, targetCenterScreen.y); - } - - - renderCombatants(); - - S2DE::Rect cursorDRect = S2DE::worldToScreenRect(&combatCam, &moveCursorPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - S2DE::renderTexture(&renderer, &arrowSprite, NULL, &cursorDRect); - - renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer - - renderActionsPanel(); - renderStatsPanel(); - SDL_RenderPresent(renderer); -} - -void selectAttackTarget(double delta) { - S2DE::updateInputState(&inputState); - - frameTimer += delta; - - if (frameTimer > frameTime) { - frameTimer = 0; - if (inputState.rtrn) { - inputState.rtrn = false; - if (targets.size() > 0) { - currentSpell = BASIC_ATTACK; - currentCombatState = DO_ATTACK; - } - else { - currentCombatState = ACTION_SELECT; - } - - } - - if (inputState.right) { - // cycle up through targets - inputState.right = false; // gotta find a better way to do this - - currentTargetIdx += 1; - if (currentTargetIdx > targets.size() - 1) currentTargetIdx = 0; - } - else if (inputState.left) { - inputState.left = false; - // cycle "down"through targets - currentTargetIdx -= 1; - if (currentTargetIdx < 0) currentTargetIdx = targets.size() - 1; - } - } - - SDL_RenderClear(renderer); - - - renderTilemap(arena, arenaWidth, arenaHeight, combatCam); - - renderCombatants(); - - // render the little red arrow above all valid targets - if (targets.size() > 0) { - S2DE::Vec2 arrowPos = targets.at(currentTargetIdx)->position; - - arrowPos.y -= 0.7; - S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - S2DE::renderTexture(&renderer, &indicatorRedSprite, NULL, &arrowDRect); - } - - - renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer - - - - renderUIFull(); - renderString(10, 10, "SELECT TARGET STATE", debug_font); - - - if (targets.size() == 0) { - renderString(10, 64, "NO TARGETS IN RANGE", debug_font); - } - else { - int num_targets = targets.size(); - char str[22]; - sprintf(str, "AVAILABLE_TARGETS: %i", num_targets); - renderString(10, 64, str, debug_font); - } - - SDL_RenderPresent(renderer); - -} - -void doAttack(double delta) { - // for now just subtract the combatants' dmg from the targets hp and move on - - - if (currentTargetIdx == -1) { - // AOE, apply to all targets in range ? - } - else { - Character* target = targets.at(currentTargetIdx); - target->currentHP -= activeCombatant->attack; - - if (target->currentHP <= 0) { - target->alive = false; - target->currentHP = 0; - } - } - - - - targets.clear(); - currentCombatState = ACTION_SELECT; - activeCombatant->canAttack = false; -} - - -void enemyMoveActionState(double delta) { - S2DE::updateInputState(&inputState); - - Character enemy = *activeCombatant; - - // implicitly grabs the character with the highest agility for now - Character agro = *std::find_if(combatants.begin(), combatants.end(), [](const Character& c) {return c.allied; }); - - S2DE::Vec2 dirToAgro = { agro.position.x - enemy.position.x, agro.position.y - enemy.position.y }; - float distToAgro = distance(enemy.position, agro.position); - - dirToAgro.x /= distToAgro; - dirToAgro.y /= distToAgro; - - S2DE::Vec2 movePos = { enemy.position.x + dirToAgro.x * enemy.moveDist, enemy.position.y + dirToAgro.y * enemy.moveDist}; - - activeCombatant->combatMoveDestination = movePos; - currentCombatState = MOVE_TO_POSITION; -} - -void movingCharacterState(double delta) { - S2DE::updateInputState(&inputState); - - frameTimer += delta; - - if (frameTimer > frameTime) { - frameTimer = 0; - - static float speed = 0.05f; - - if (inputState.rtrn) { - // skip - inputState.rtrn = false; - activeCombatant->position = activeCombatant->combatMoveDestination; - } - - moveToPosition(activeCombatant, activeCombatant->combatMoveDestination, speed); - - if (activeCombatant->position.x == activeCombatant->combatMoveDestination.x && activeCombatant->position.y == activeCombatant->combatMoveDestination.y) { - // move completed. if allied, return to select action - if (activeCombatant->allied) { - activeCombatant->canMove = false; // TODO: support characters that can move twice? - currentCombatState = ACTION_SELECT; - } - else { - currentCombatState = TURN_ORDER; - } - } - - // TODO: Ensure all rendering is happening at the same FPS - SDL_RenderClear(renderer); - renderCombat(); - // dont show the ui in this state - SDL_RenderPresent(renderer); - } - -} - - -void determineNextTurnState(double delta) { - - currentCombatantIndex += 1; - - // WARNING: this system does not support the case where agility changes mid-fight. will need to re-sort if that happens - if (currentCombatantIndex > combatants.size() - 1) currentCombatantIndex = 0; - - activeCombatant = &combatants.at(currentCombatantIndex); - - if (activeCombatant->alive) { // skip dead characters - if (activeCombatant->allied) { - // reset combatants actions - activeCombatant->canAttack = true; - activeCombatant->canMove = true; - currentAction = 0; - currentCombatState = ACTION_SELECT; - } - else { - //currentCombatState = ENEMY_MOVE; - } - } - -} - - -void runCombat(double delta) { - - static double frameTimer = 0; - static const double frameTime = 1.0f / 60.0f; - - runStateFunction(currentCombatState, delta); - +#define _CRT_SECURE_NO_WARNINGS + +#include "combat.h" +#include "globals.h" +#include "ui.h" +#include "tilemap.h" + +#include +#include + + +struct Character { + bool allied; + std::string name; + int currentHP; + int maxHP; + int currentMP; + int maxMP; + int attack; + float agility; // to determine move order + float moveDist; + + // animation stuff? + SDL_Texture* texture; + S2DE::Vec2 position; + // direction vector? + // how to handle "moves" + S2DE::Vec2 combatMoveDestination = { 0.0f, 0.0f }; + + int basicAttackRange = 1.0f; + + bool canMove = true; + bool canAttack = true; + + bool alive = true; +}; + +std::vector combatants; +int currentCombatantIndex = -1; +Character* activeCombatant; + +std::vector targets; +int currentTargetIdx = 0; + +enum CombatState { + TURN_ORDER, + ACTION_SELECT, + PLAYER_MOVE, + SELECT_TARGET, + DO_ATTACK, + ENEMY_MOVE, + MOVE_TO_POSITION, +}; + +CombatState currentCombatState = TURN_ORDER; + +enum Spell { + BASIC_ATTACK +}; + +Spell currentSpell = BASIC_ATTACK; + +static double frameTimer = 0; +static const double frameTime = 1.0f / 60.0f; + +//bool playerTurn = true; + +SDL_Texture* arrowSprite = nullptr; +SDL_Texture* indicatorSprite = nullptr; +SDL_Texture* indicatorRedSprite = nullptr; + +static constexpr int arenaWidth = 100; +static constexpr int arenaHeight = 100; +WorldCell** arena; +WorldCell** fogLayer; +S2DE::Camera combatCam = { 23.5, 11.5 }; + +S2DE::Vec2 moveCursorPos; +S2DE::Vec2 arenaCenter = { 23, 11 }; + +//S2DE::Vec2* currentMoveDest = &moveCursorPos; + +static const int numActions = 4; +static const char* actions[numActions] = {"Move", "Attack", "End", "FLEE"}; +int currentAction = 0; + +SDL_Colour hpColour = { 136, 8, 8, 255 }; +SDL_Colour mpColour = { 0, 150, 255, 255 }; + +void renderCombat(); + +void renderUIFull(); +void renderActionsPanel(); +void renderCombatants(); +void renderStatsPanel(); + +// lerp functions +float interpolatePosition(S2DE::Vec2* entityPos, S2DE::Vec2 destination, float t, float speed); +void moveToPosition(Character* c, S2DE::Vec2 destination, float speed); + +void runStateFunction(CombatState state, double delta); +void actionSelectState(double delta); +void playerMoveActionState(double delta); +void enemyMoveActionState(double delta); +void movingCharacterState(double delta); +void determineNextTurnState(double delta); +void selectAttackTarget(double delta); +void doAttack(double delta); // plays attack animation, resolves and applies damage. + +void runStateFunction(CombatState state, double delta) { + switch (state) { + case TURN_ORDER: determineNextTurnState(delta); break; + case ACTION_SELECT: actionSelectState(delta); break; + case PLAYER_MOVE: playerMoveActionState(delta); break; + case SELECT_TARGET: selectAttackTarget(delta); break; + case ENEMY_MOVE: enemyMoveActionState(delta); break; + case MOVE_TO_POSITION: movingCharacterState(delta); break; + case DO_ATTACK: doAttack(delta); break; + default: assert(false); break; + } +} + +float distance(S2DE::Vec2 p1, S2DE::Vec2 p2) { + return std::sqrt(std::pow(p2.x - p1.x, 2) + std::powf(p2.y - p1.y, 2)); +} + +void renderMeter(int x, int y, int width, int height, float percentage, SDL_Colour fillColour, int style) { + if (style == 1) { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 180); + SDL_Rect bgRect = { x, y, width, height }; + SDL_RenderFillRect(renderer, &bgRect); + } + else if (style == 2) { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderDrawLine(renderer, x, y, x + width, y); + SDL_RenderDrawLine(renderer, x, y + height, x + width, y + height); + + SDL_RenderDrawLine(renderer, x, y, x, y + height); + SDL_RenderDrawLine(renderer, x + width, y, x + width, y + height); + } + + SDL_SetRenderDrawColor(renderer, fillColour.r, fillColour.g, fillColour.b, fillColour.a); + int panelWidth = width * percentage; + SDL_Rect fillRect = { x+1, y+1, panelWidth -1, height-1 }; + SDL_RenderFillRect(renderer, &fillRect); +} + +void renderStatsPanel() { + int panelWidth = 300; + int panelHeight = 200; + int outerPad = 2; + int innerPad = 16; + + int panelX = WINDOW_WIDTH - panelWidth - outerPad; + int panelY = WINDOW_HEIGHT - panelHeight - outerPad; + + renderBasicPanel(panelX, panelY, panelWidth, panelHeight); + renderString(panelX + innerPad, panelY + innerPad, activeCombatant->name.c_str()); + + int portraitWidth = 80; + int portraitHeight = 80; + + int portraitX = panelX + 16; + int portraitY = panelY + 50; + renderBasicPanel(portraitX, portraitY, portraitWidth, portraitHeight); + SDL_Rect characterDRect = { portraitX + 8, portraitY + 8, portraitWidth - 16, portraitHeight - 16}; + SDL_Rect characterSRect = { 0 , 0, 32, 32 }; + SDL_Texture* portraitTexture = activeCombatant->texture; + S2DE::renderTexture(&renderer, &portraitTexture, &characterSRect, &characterDRect); + + + renderString(portraitX + portraitWidth + innerPad, portraitY, "HP:"); + int valPad = 100; + char hpStr[10]; + sprintf(hpStr, "%d/%d", activeCombatant->currentHP, activeCombatant->maxHP); + renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, hpStr); + + float hpLvl = (float)activeCombatant->currentHP / (float)activeCombatant->maxHP; + renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, hpLvl, hpColour, 2); + + renderString(portraitX + portraitWidth + innerPad, portraitY + innerPad + 22, "MP:"); + + char mpStr[10]; + sprintf(mpStr, "%d/%d", activeCombatant->currentMP, activeCombatant->maxMP); + renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, mpStr); + + float mpLvl = (float)activeCombatant->currentMP / (float)activeCombatant->maxMP; + renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, mpLvl, mpColour, 2); + +} + +void renderActionsPanel() { + int panelWidth = 150; + int panelHeight = 150; + + //int panelX = WINDOW_WIDTH / 2 - panelWidth / 2; + int panelX = 100; + int panelY = WINDOW_HEIGHT - panelHeight - 2; + + renderBasicPanel(panelX, panelY, panelWidth, panelHeight); + + int leftPad = 40; + int topPad = 20; + int itemSpacing = 30; + + for (int i = 0; i < numActions; ++i) { + // a bit of a brittle way of doing this + if (i == 0 && !activeCombatant->canMove) { + renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey); + } + else if (i == 1 && !activeCombatant->canAttack) { + renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i], font_grey); + } + else { + renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, actions[i]); + } + } + + renderString(panelX + 20, panelY + topPad + (itemSpacing * currentAction), ">"); +} + +void renderUIFull() { + renderActionsPanel(); + renderStatsPanel(); +} + +void renderCombat() { + renderTilemap(arena, arenaWidth, arenaHeight, combatCam); + renderCombatants(); + renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // render the fog layer +} + +void renderCombatants() { + + for (Character c : combatants) { + + if (c.alive) { + S2DE::Vec2 pos = c.position; + S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::Rect charSRect = { 0, 0, 32, 32 }; + + // disabled for now + //if (c.allied) { + // // do the looking logic only for allied characters + // int playerFrame = 1; + // int playerDir = 0; + + // Character enemy = combatants.at(1); + + // int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5); + // int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5); + + // if (abs(lookDeltaX) > abs(lookDeltaY)) { + // if (lookDeltaX > 0) playerDir = 2; + // else playerDir = 6; + // } + // else { + // if (lookDeltaY > 0) playerDir = 4; + // else playerDir = 0; + // } + + // charSRect = { playerFrame * 32, playerDir * 32, 32, 32 }; + //} + + SDL_Texture* texture = c.texture; + S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect); + + float hpLvl = (float)c.currentHP / (float)c.maxHP; + renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, hpLvl, hpColour, 1); + } + } + + // render the little arrow + S2DE::Vec2 arrowPos = activeCombatant->position; + + arrowPos.y -= 0.7; + S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::renderTexture(&renderer, &indicatorSprite, NULL, &arrowDRect); +} + +void initCombatScene() +{ + // I think all resources should be initialized and cleaned up in the globals tbh + arena = new WorldCell * [arenaHeight]; + for (int i = 0; i < arenaHeight; ++i) arena[i] = new WorldCell[arenaWidth]; + + fogLayer = new WorldCell * [arenaHeight]; + for (int i = 0; i < arenaHeight; ++i) fogLayer[i] = new WorldCell[arenaWidth]; + + loadWorld("maps/combat_arena_1.tmj", arena, arenaWidth, arenaHeight); + loadWorld("maps/combat_arena_1_fog.tmj", fogLayer, arenaWidth, arenaHeight); + + arrowSprite = S2DE::loadTexture("assets/arrow.png", &renderer); + indicatorSprite = S2DE::loadTexture("assets/little_indicator.png", &renderer); + indicatorRedSprite = S2DE::loadTexture("assets/little_indicator_red.png", &renderer); + + //Character player = { true, "Player", 100, 100, 50, 50, 10.0f, 3.0f, player_sheet, { 23.0f, 13.0f } }; + Character player; + player.allied = true; + player.name = "Player"; + player.maxHP = 100; + player.currentHP = player.maxHP; + player.maxMP = 50; + player.currentMP = player.maxMP; + player.agility = 10.0f; + player.moveDist = 3.0f; + player.texture = player_forward_texture; + player.position = { arenaCenter.x, arenaCenter.y + 2 }; + player.attack = 5; + + + Character monica; + monica.allied = true; + monica.name = "Monica"; + monica.maxHP = 100; + monica.currentHP = monica.maxHP; + monica.maxMP = 50; + monica.currentMP = monica.maxMP; + monica.agility = 8.0f; + monica.moveDist = 6.0f; + monica.texture = monica_texture; + monica.position = { player.position.x - 2, player.position.y }; + monica.attack = 6; + + Character enemy; + enemy.allied = false; + enemy.name = "Bird"; + enemy.maxHP = 25; + enemy.currentHP = enemy.maxHP; + enemy.maxMP = 10; + enemy.currentMP = enemy.maxMP; + enemy.agility = 5.0f; + enemy.moveDist = 1.5f; + enemy.texture = bird; + enemy.position = { arenaCenter.x, arenaCenter.y - 2 }; + enemy.attack = 2; + + Character frog; + frog.allied = false; + frog.name = "Frog"; + frog.currentHP = frog.maxHP = 10; + frog.currentMP = frog.maxMP = 10; + frog.agility = 2; + frog.moveDist = 2.0f; + frog.texture = frog_texture; + frog.position = { arenaCenter.x - 1, arenaCenter.y - 2 }; + frog.attack = 2; + + combatants.push_back(player); + combatants.push_back(monica); + combatants.push_back(enemy); + combatants.push_back(frog); + + + // calculates turn order. Can expand the lambda to support other things + std::sort(combatants.begin(), combatants.end(), [](const Character& a, const Character& b) {return a.agility > b.agility; }); + + activeCombatant = &combatants.at(0); + moveCursorPos = activeCombatant->position; +} + + +void interpolatePosition(S2DE::Vec2* entityPos, S2DE::Vec2 destination, float* t, float speed) { + *t += speed; + + entityPos->x = (1.0f - *t) * entityPos->x + *t * destination.x; + entityPos->y = (1.0f - *t) * entityPos->y + *t * destination.y; +} + +void moveToPosition(Character* c, S2DE::Vec2 destination, float speed) { + float dist = distance(c->position, destination); + + S2DE::Vec2 direction {destination.x - c->position.x, destination.y - c->position.y}; + + direction.x /= dist; + direction.y /= dist; + + if (dist <= speed) { + c->position.x = destination.x; + c->position.y = destination.y; + } + else { + c->position.x += direction.x * speed; + c->position.y += direction.y * speed; + } +} + +void actionSelectState(double delta) { + S2DE::updateInputState(&inputState); + + // handle inputs + if (inputState.up) { + inputState.up = false; + currentAction--; + if (currentAction < 0) currentAction = numActions - 1; + } + else if (inputState.down) { + inputState.down = false; + currentAction++; + if (currentAction > numActions - 1) currentAction = 0; + } + else if (inputState.rtrn) { + inputState.rtrn = false; + switch (currentAction) { + case 0: + if (activeCombatant->canMove) { + currentCombatState = PLAYER_MOVE; + moveCursorPos = activeCombatant->position; + } + break; + case 1: // attack selected + if (activeCombatant->canAttack) { + // filter the targets - Have to do it here too in case the player attacks without moving? + targets.clear(); + for (auto& c : combatants) { + if (!c.allied && c.alive) { + float dist = distance(activeCombatant->position, c.position); + if (dist <= activeCombatant->basicAttackRange) { + targets.push_back(&c); + } + } + } + + currentCombatState = SELECT_TARGET; + } + break; + case 2: // end selected + currentCombatState = TURN_ORDER; + break; + + default: + inputState.quit = true; + break; + } + } + + SDL_RenderClear(renderer); + renderCombat(); + renderUIFull(); + SDL_RenderPresent(renderer); +} + +void playerMoveActionState(double delta) { + S2DE::updateInputState(&inputState); + + frameTimer += delta; + + Character player = *activeCombatant; + + if (frameTimer > frameTime) { + + frameTimer = 0; + + float cursorSpeed = 0.05; + + S2DE::Vec2 newCursorPos = moveCursorPos; + + float newY = moveCursorPos.y; + float newX = moveCursorPos.x; + + if (inputState.right) { + newX += cursorSpeed; + } + if (inputState.left) { + newX -= cursorSpeed; + } + if (inputState.up) { + newY -= cursorSpeed; + } + if (inputState.down) { + newY += cursorSpeed; + } + + if (inputState.rtrn) { + inputState.rtrn = false; + + activeCombatant->combatMoveDestination = moveCursorPos; + currentCombatState = MOVE_TO_POSITION; + } + + if (distance({ moveCursorPos.x, newY }, player.position) <= player.moveDist + && checkCollisionPoint({ moveCursorPos.x + 0.5f, newY + 0.5f }, arena) == false) { + moveCursorPos.y = newY; + } + if (distance({ newX, moveCursorPos.y }, player.position) <= player.moveDist + && checkCollisionPoint({ newX + 0.5f, moveCursorPos.y + 0.5f }, arena) == false) { + moveCursorPos.x = newX; + } + + } + + + // compute characters in melee range + targets.clear(); + for (auto& c : combatants) { + if (!c.allied && c.alive) { + float dist = distance(moveCursorPos, c.position); + if (dist <= activeCombatant->basicAttackRange) { + targets.push_back(&c); + } + } + } + + + SDL_RenderClear(renderer); + + renderTilemap(arena, arenaWidth, arenaHeight, combatCam); + + + S2DE::Vec2 playerCenterWorld = { player.position.x + 0.5, player.position.y + 0.5 }; + S2DE::Vec2 playerCenterScreen = S2DE::worldToScreenPoint(&combatCam, &playerCenterWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT); + + S2DE::renderCircle(&renderer, playerCenterScreen, (player.moveDist) * 64, { 0, 255, 255, 125 }); + + + S2DE::Vec2 lineEndWorld = { moveCursorPos.x + 0.5, moveCursorPos.y + 0.5 }; + S2DE::Vec2 lineEndPos = S2DE::worldToScreenPoint(&combatCam, &lineEndWorld, 64, WINDOW_WIDTH, WINDOW_HEIGHT); + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDrawLine(renderer, playerCenterScreen.x, playerCenterScreen.y, lineEndPos.x, lineEndPos.y); + + // render lines to targets in range + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + for (auto t : targets) { + S2DE::Vec2 targetCenter = { t->position.x + 0.5, t->position.y + 0.5 }; + S2DE::Vec2 targetCenterScreen = S2DE::worldToScreenPoint(&combatCam, &targetCenter, 64, WINDOW_WIDTH, WINDOW_HEIGHT); + SDL_RenderDrawLine(renderer, lineEndPos.x, lineEndPos.y, targetCenterScreen.x, targetCenterScreen.y); + } + + + renderCombatants(); + + S2DE::Rect cursorDRect = S2DE::worldToScreenRect(&combatCam, &moveCursorPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::renderTexture(&renderer, &arrowSprite, NULL, &cursorDRect); + + renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer + + renderActionsPanel(); + renderStatsPanel(); + SDL_RenderPresent(renderer); +} + +void selectAttackTarget(double delta) { + S2DE::updateInputState(&inputState); + + frameTimer += delta; + + if (frameTimer > frameTime) { + frameTimer = 0; + if (inputState.rtrn) { + inputState.rtrn = false; + if (targets.size() > 0) { + currentSpell = BASIC_ATTACK; + currentCombatState = DO_ATTACK; + } + else { + currentCombatState = ACTION_SELECT; + } + + } + + if (inputState.right) { + // cycle up through targets + inputState.right = false; // gotta find a better way to do this + + currentTargetIdx += 1; + if (currentTargetIdx > targets.size() - 1) currentTargetIdx = 0; + } + else if (inputState.left) { + inputState.left = false; + // cycle "down"through targets + currentTargetIdx -= 1; + if (currentTargetIdx < 0) currentTargetIdx = targets.size() - 1; + } + } + + SDL_RenderClear(renderer); + + + renderTilemap(arena, arenaWidth, arenaHeight, combatCam); + + renderCombatants(); + + // render the little red arrow above all valid targets + if (targets.size() > 0) { + S2DE::Vec2 arrowPos = targets.at(currentTargetIdx)->position; + + arrowPos.y -= 0.7; + S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::renderTexture(&renderer, &indicatorRedSprite, NULL, &arrowDRect); + } + + + renderTilemap(fogLayer, arenaWidth, arenaHeight, combatCam); // draw the fog layer + + + + renderUIFull(); + renderString(10, 10, "SELECT TARGET STATE", debug_font); + + + if (targets.size() == 0) { + renderString(10, 64, "NO TARGETS IN RANGE", debug_font); + } + else { + int num_targets = targets.size(); + char str[22]; + sprintf(str, "AVAILABLE_TARGETS: %i", num_targets); + renderString(10, 64, str, debug_font); + } + + SDL_RenderPresent(renderer); + +} + +void doAttack(double delta) { + // for now just subtract the combatants' dmg from the targets hp and move on + + + if (currentTargetIdx == -1) { + // AOE, apply to all targets in range ? + } + else { + Character* target = targets.at(currentTargetIdx); + target->currentHP -= activeCombatant->attack; + + if (target->currentHP <= 0) { + target->alive = false; + target->currentHP = 0; + } + } + + + + targets.clear(); + currentCombatState = ACTION_SELECT; + activeCombatant->canAttack = false; +} + + +void enemyMoveActionState(double delta) { + S2DE::updateInputState(&inputState); + + Character enemy = *activeCombatant; + + // implicitly grabs the character with the highest agility for now + Character agro = *std::find_if(combatants.begin(), combatants.end(), [](const Character& c) {return c.allied; }); + + S2DE::Vec2 dirToAgro = { agro.position.x - enemy.position.x, agro.position.y - enemy.position.y }; + float distToAgro = distance(enemy.position, agro.position); + + dirToAgro.x /= distToAgro; + dirToAgro.y /= distToAgro; + + S2DE::Vec2 movePos = { enemy.position.x + dirToAgro.x * enemy.moveDist, enemy.position.y + dirToAgro.y * enemy.moveDist}; + + activeCombatant->combatMoveDestination = movePos; + currentCombatState = MOVE_TO_POSITION; +} + +void movingCharacterState(double delta) { + S2DE::updateInputState(&inputState); + + frameTimer += delta; + + if (frameTimer > frameTime) { + frameTimer = 0; + + static float speed = 0.05f; + + if (inputState.rtrn) { + // skip + inputState.rtrn = false; + activeCombatant->position = activeCombatant->combatMoveDestination; + } + + moveToPosition(activeCombatant, activeCombatant->combatMoveDestination, speed); + + if (activeCombatant->position.x == activeCombatant->combatMoveDestination.x && activeCombatant->position.y == activeCombatant->combatMoveDestination.y) { + // move completed. if allied, return to select action + if (activeCombatant->allied) { + activeCombatant->canMove = false; // TODO: support characters that can move twice? + currentCombatState = ACTION_SELECT; + } + else { + currentCombatState = TURN_ORDER; + } + } + + // TODO: Ensure all rendering is happening at the same FPS + SDL_RenderClear(renderer); + renderCombat(); + // dont show the ui in this state + SDL_RenderPresent(renderer); + } + +} + + +void determineNextTurnState(double delta) { + + currentCombatantIndex += 1; + + // WARNING: this system does not support the case where agility changes mid-fight. will need to re-sort if that happens + if (currentCombatantIndex > combatants.size() - 1) currentCombatantIndex = 0; + + activeCombatant = &combatants.at(currentCombatantIndex); + + if (activeCombatant->alive) { // skip dead characters + if (activeCombatant->allied) { + // reset combatants actions + activeCombatant->canAttack = true; + activeCombatant->canMove = true; + currentAction = 0; + currentCombatState = ACTION_SELECT; + } + else { + //currentCombatState = ENEMY_MOVE; + } + } + +} + + +void runCombat(double delta) { + + static double frameTimer = 0; + static const double frameTime = 1.0f / 60.0f; + + runStateFunction(currentCombatState, delta); + } \ No newline at end of file diff --git a/combat.h b/combat.h index 71bd349..613bd3e 100644 --- a/combat.h +++ b/combat.h @@ -1,5 +1,5 @@ -#pragma once - -void initCombatScene(); - +#pragma once + +void initCombatScene(); + void runCombat(double deltaTime); \ No newline at end of file diff --git a/globals.cpp b/globals.cpp index e3db2d1..7689f2f 100644 --- a/globals.cpp +++ b/globals.cpp @@ -1,41 +1,41 @@ -#include "globals.h" - -SDL_Texture* environment_sheet = nullptr; -SDL_Texture* player_sheet = nullptr; -SDL_Texture* water_test_sheet = nullptr; -SDL_Texture* font_sheet = nullptr; -SDL_Texture* debug_font = nullptr; -SDL_Texture* font_grey = nullptr; -SDL_Texture* ui_frame_sheet = nullptr; -SDL_Texture* bird = nullptr; -SDL_Texture* monica_texture = nullptr; -SDL_Texture* player_forward_texture = nullptr; -SDL_Texture* frog_texture = nullptr; -Mix_Music* background_music = nullptr; - - -static const char* environment_sheet_path = "assets/dragon_survivors_environment_1.png"; -static const char* player_sheet_path = "assets/player.png"; -static const char* water_test_sheet_path = "assets/water_test.png"; -static const char* font_sheet_path = "assets/simple_6x8_black.png"; -static const char* ui_frame_sheet_path = "assets/frame.png"; -static const char* bird_path = "assets/bird_32.png"; -static const char* bg_mus_path = "assets/TownTheme.mp3"; - -void initResources() -{ - environment_sheet = S2DE::loadTexture(environment_sheet_path, &renderer); - player_sheet = S2DE::loadTexture(player_sheet_path, &renderer); - water_test_sheet = S2DE::loadTexture(water_test_sheet_path, &renderer); - font_sheet = S2DE::loadTexture(font_sheet_path, &renderer); - debug_font = S2DE::loadTexture("assets/simple_6x8_red.png", &renderer); - font_grey = S2DE::loadTexture("assets/simple_6x8_grey.png", &renderer); - ui_frame_sheet = S2DE::loadTexture(ui_frame_sheet_path, &renderer); - bird = S2DE::loadTexture(bird_path, &renderer); - - monica_texture = S2DE::loadTexture("assets/Monica_sprite.png", &renderer); - player_forward_texture = S2DE::loadTexture("assets/player_forward.png", &renderer); - frog_texture = S2DE::loadTexture("assets/Frog_sprite.png", &renderer); - background_music = Mix_LoadMUS(bg_mus_path); -} - +#include "globals.h" + +SDL_Texture* environment_sheet = nullptr; +SDL_Texture* player_sheet = nullptr; +SDL_Texture* water_test_sheet = nullptr; +SDL_Texture* font_sheet = nullptr; +SDL_Texture* debug_font = nullptr; +SDL_Texture* font_grey = nullptr; +SDL_Texture* ui_frame_sheet = nullptr; +SDL_Texture* bird = nullptr; +SDL_Texture* monica_texture = nullptr; +SDL_Texture* player_forward_texture = nullptr; +SDL_Texture* frog_texture = nullptr; +Mix_Music* background_music = nullptr; + + +static const char* environment_sheet_path = "assets/dragon_survivors_environment_1.png"; +static const char* player_sheet_path = "assets/player.png"; +static const char* water_test_sheet_path = "assets/water_test.png"; +static const char* font_sheet_path = "assets/simple_6x8_black.png"; +static const char* ui_frame_sheet_path = "assets/frame.png"; +static const char* bird_path = "assets/bird_32.png"; +static const char* bg_mus_path = "assets/TownTheme.mp3"; + +void initResources() +{ + environment_sheet = S2DE::loadTexture(environment_sheet_path, &renderer); + player_sheet = S2DE::loadTexture(player_sheet_path, &renderer); + water_test_sheet = S2DE::loadTexture(water_test_sheet_path, &renderer); + font_sheet = S2DE::loadTexture(font_sheet_path, &renderer); + debug_font = S2DE::loadTexture("assets/simple_6x8_red.png", &renderer); + font_grey = S2DE::loadTexture("assets/simple_6x8_grey.png", &renderer); + ui_frame_sheet = S2DE::loadTexture(ui_frame_sheet_path, &renderer); + bird = S2DE::loadTexture(bird_path, &renderer); + + monica_texture = S2DE::loadTexture("assets/Monica_sprite.png", &renderer); + player_forward_texture = S2DE::loadTexture("assets/player_forward.png", &renderer); + frog_texture = S2DE::loadTexture("assets/Frog_sprite.png", &renderer); + background_music = Mix_LoadMUS(bg_mus_path); +} + diff --git a/globals.h b/globals.h index 9d25677..4d743e9 100644 --- a/globals.h +++ b/globals.h @@ -1,57 +1,57 @@ -#pragma once - -#include -#include -#include -#include <2DEngine.h> - - -#define WINDOW_WIDTH 1280 -#define WINDOW_HEIGHT 720 - -extern SDL_Window* window; -extern SDL_Renderer* renderer; - - -// maybe a resources.h? -extern SDL_Texture* environment_sheet; -extern SDL_Texture* player_sheet; -extern SDL_Texture* water_test_sheet; -extern SDL_Texture* font_sheet; -extern SDL_Texture* debug_font; -extern SDL_Texture* font_grey; -extern SDL_Texture* ui_frame_sheet; -extern SDL_Texture* bird; -extern SDL_Texture* monica_texture; -extern SDL_Texture* player_forward_texture; -extern SDL_Texture* frog_texture; - -extern Mix_Music* background_music; - -void initResources(); - -extern S2DE::InputState inputState; - -// These things should be defined in the overworld -extern S2DE::Vec2 playerPos; -extern int playerFrame; -extern int playerDir; - -extern S2DE::Vec2 birdPos; -extern bool enemyDirection; // 0 = left, 1 = right - -#define WORLD_HEIGHT 200 -#define WORLD_WIDTH 200 - -//extern WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]; - -extern S2DE::Camera camera; - -enum GameState -{ - MAIN_MENU, - OVERWORLD, - COMBAT -}; - +#pragma once + +#include +#include +#include +#include <2DEngine.h> + + +#define WINDOW_WIDTH 1280 +#define WINDOW_HEIGHT 720 + +extern SDL_Window* window; +extern SDL_Renderer* renderer; + + +// maybe a resources.h? +extern SDL_Texture* environment_sheet; +extern SDL_Texture* player_sheet; +extern SDL_Texture* water_test_sheet; +extern SDL_Texture* font_sheet; +extern SDL_Texture* debug_font; +extern SDL_Texture* font_grey; +extern SDL_Texture* ui_frame_sheet; +extern SDL_Texture* bird; +extern SDL_Texture* monica_texture; +extern SDL_Texture* player_forward_texture; +extern SDL_Texture* frog_texture; + +extern Mix_Music* background_music; + +void initResources(); + +extern S2DE::InputState inputState; + +// These things should be defined in the overworld +extern S2DE::Vec2 playerPos; +extern int playerFrame; +extern int playerDir; + +extern S2DE::Vec2 birdPos; +extern bool enemyDirection; // 0 = left, 1 = right + +#define WORLD_HEIGHT 200 +#define WORLD_WIDTH 200 + +//extern WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]; + +extern S2DE::Camera camera; + +enum GameState +{ + MAIN_MENU, + OVERWORLD, + COMBAT +}; + extern GameState gameState; \ No newline at end of file diff --git a/main.cpp b/main.cpp index fe47b97..a86bab2 100644 --- a/main.cpp +++ b/main.cpp @@ -1,229 +1,229 @@ -#include -#include -#include -#include -#include -#include - -#include <2DEngine.h> - -#include "globals.h" -#include "main_menu.h" -#include "combat.h" -#include "tilemap.h" - -GameState gameState = MAIN_MENU; -//GameState gameState = COMBAT; - -using json = nlohmann::json; - -SDL_Window* window = nullptr; -SDL_Renderer* renderer = nullptr; - -S2DE::InputState inputState; - - -WorldCell** world; - -S2DE::Camera camera; - -// These things should be defined in the overworld -S2DE::Vec2 playerPos = { 30, 19 }; -int playerFrame = 0; -int playerDir = 4; - -S2DE::Vec2 birdPos = { 31, 16 }; -bool enemyDirection = 0; // 0 = left, 1 = right - -//void loadWorld(const char* worldPath, WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]); - -//S2DE::Rect renderString(int startX, int startY, const char* string); -void renderWorld(); -//void renderUI(); - -//bool checkCollision(S2DE::Vec2 worldPos); - - -void renderWorld() -{ - - // render enemy - - S2DE::Rect enemyDRect = S2DE::worldToScreenRect(&camera, &birdPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - S2DE::Rect enemySRect = { 0, 32 * enemyDirection, 32, 32 }; - S2DE::renderTexture(&renderer, &bird, &enemySRect, &enemyDRect); - - - // render player - - S2DE::Rect playerDRect = S2DE::worldToScreenRect(&camera, &playerPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); - - S2DE::Rect playerSRect = { playerFrame * 32, playerDir * 32, 32, 32 }; - S2DE::renderTexture(&renderer, &player_sheet, &playerSRect, &playerDRect); - -} - -int main(int argc, char** args) -{ - S2DE::initRendering("Dragon Survivors", WINDOW_WIDTH, WINDOW_HEIGHT, &window, &renderer); - initResources(); - initCombatScene(); - - world = new WorldCell * [WORLD_HEIGHT]; - for (int i = 0; i < WORLD_HEIGHT; ++i) world[i] = new WorldCell[WORLD_WIDTH]; - - loadWorld("maps/overworld_1.tmj", world, WORLD_WIDTH, WORLD_HEIGHT); - - bool running = true; - - double currentTime = 0.0; - double last = 0.0; - double delta = 0.0; - - double frameCounter = 0; - double frameTime = 1.0 / 60; // 60 hrz - - double animCounter = 0; - double animTime = 1.0 / 3; - - - double enemyWalkTime = 0.5; // walks each dir for 2 seconds - double enemyWalkTimer = 0; - - - Mix_VolumeMusic(MIX_MAX_VOLUME / 4); - //Mix_PlayMusic(background_music, -1); - - while (inputState.quit != true) - { - currentTime = SDL_GetTicks(); - delta = (currentTime - last) / 1000.0f; - last = currentTime; - - if (gameState == MAIN_MENU) - { - mainMenu(delta); - } - else if (gameState == OVERWORLD) - { - - frameCounter += delta; - animCounter += delta; - - enemyWalkTimer += delta; - - S2DE::updateInputState(&inputState); - - if (frameCounter > frameTime) - { - frameCounter = 0; - - // update player - float walkSpeed = 0.08; - - float newX = playerPos.x; - float newY = playerPos.y; - float finalX = newX; - float finalY = newY; - - if (inputState.right) { - newX += walkSpeed; - playerDir = 2; - } - if (inputState.left) { - newX -= walkSpeed; - playerDir = 6; - } - if (inputState.up) { - newY -= walkSpeed; - playerDir = 0; - } - if (inputState.down) { - newY += walkSpeed; - playerDir = 4; - } - - if (!checkCollisionRect({ playerPos.x, newY }, world)) - { - // can move on the y - finalY = newY; - } - - if (!checkCollisionRect({ newX, playerPos.y }, world)) - { - // can move on the X - finalX = newX; - } - - playerPos.x = finalX; - playerPos.y = finalY; - - camera = playerPos; - - if (enemyWalkTimer > enemyWalkTime) - { - // flip the direction and reset the timer - enemyDirection = !enemyDirection; - enemyWalkTimer = 0; - } - - float enemyWalkSpeed = 0.04; - if (enemyDirection) // true == 1 == going right - { - birdPos.x += enemyWalkSpeed; - } - else // going left - { - birdPos.x -= enemyWalkSpeed; - } - - } - - - static bool forward = true; - if (animCounter >= animTime) - { - animCounter = 0; - - if (forward) - { - playerFrame += 1; - if (playerFrame >= 2) - { - forward = false; - } - } - else - { - playerFrame -= 1; - if (playerFrame <= 0) - { - forward = true; - } - } - } - - SDL_RenderClear(renderer); - { - renderTilemap(world, WORLD_WIDTH, WORLD_HEIGHT, camera); - renderWorld(); - } - SDL_RenderPresent(renderer); - } - else if (gameState == COMBAT) { - runCombat(delta); - } - } - - - for (int i = 0; i < WORLD_HEIGHT; ++i) delete[] world[i]; - delete[] world; - - S2DE::quitRendering(&renderer, &window); - Mix_Quit(); - - SDL_DestroyTexture(environment_sheet); - // destroy the other shit here - // add mix_quit to dll - return 0; +#include +#include +#include +#include +#include +#include + +#include <2DEngine.h> + +#include "globals.h" +#include "main_menu.h" +#include "combat.h" +#include "tilemap.h" + +GameState gameState = MAIN_MENU; +//GameState gameState = COMBAT; + +using json = nlohmann::json; + +SDL_Window* window = nullptr; +SDL_Renderer* renderer = nullptr; + +S2DE::InputState inputState; + + +WorldCell** world; + +S2DE::Camera camera; + +// These things should be defined in the overworld +S2DE::Vec2 playerPos = { 30, 19 }; +int playerFrame = 0; +int playerDir = 4; + +S2DE::Vec2 birdPos = { 31, 16 }; +bool enemyDirection = 0; // 0 = left, 1 = right + +//void loadWorld(const char* worldPath, WorldCell world[WORLD_HEIGHT][WORLD_WIDTH]); + +//S2DE::Rect renderString(int startX, int startY, const char* string); +void renderWorld(); +//void renderUI(); + +//bool checkCollision(S2DE::Vec2 worldPos); + + +void renderWorld() +{ + + // render enemy + + S2DE::Rect enemyDRect = S2DE::worldToScreenRect(&camera, &birdPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::Rect enemySRect = { 0, 32 * enemyDirection, 32, 32 }; + S2DE::renderTexture(&renderer, &bird, &enemySRect, &enemyDRect); + + + // render player + + S2DE::Rect playerDRect = S2DE::worldToScreenRect(&camera, &playerPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + + S2DE::Rect playerSRect = { playerFrame * 32, playerDir * 32, 32, 32 }; + S2DE::renderTexture(&renderer, &player_sheet, &playerSRect, &playerDRect); + +} + +int main(int argc, char** args) +{ + S2DE::initRendering("Dragon Survivors", WINDOW_WIDTH, WINDOW_HEIGHT, &window, &renderer); + initResources(); + initCombatScene(); + + world = new WorldCell * [WORLD_HEIGHT]; + for (int i = 0; i < WORLD_HEIGHT; ++i) world[i] = new WorldCell[WORLD_WIDTH]; + + loadWorld("maps/overworld_1.tmj", world, WORLD_WIDTH, WORLD_HEIGHT); + + bool running = true; + + double currentTime = 0.0; + double last = 0.0; + double delta = 0.0; + + double frameCounter = 0; + double frameTime = 1.0 / 60; // 60 hrz + + double animCounter = 0; + double animTime = 1.0 / 3; + + + double enemyWalkTime = 0.5; // walks each dir for 2 seconds + double enemyWalkTimer = 0; + + + Mix_VolumeMusic(MIX_MAX_VOLUME / 4); + //Mix_PlayMusic(background_music, -1); + + while (inputState.quit != true) + { + currentTime = SDL_GetTicks(); + delta = (currentTime - last) / 1000.0f; + last = currentTime; + + if (gameState == MAIN_MENU) + { + mainMenu(delta); + } + else if (gameState == OVERWORLD) + { + + frameCounter += delta; + animCounter += delta; + + enemyWalkTimer += delta; + + S2DE::updateInputState(&inputState); + + if (frameCounter > frameTime) + { + frameCounter = 0; + + // update player + float walkSpeed = 0.08; + + float newX = playerPos.x; + float newY = playerPos.y; + float finalX = newX; + float finalY = newY; + + if (inputState.right) { + newX += walkSpeed; + playerDir = 2; + } + if (inputState.left) { + newX -= walkSpeed; + playerDir = 6; + } + if (inputState.up) { + newY -= walkSpeed; + playerDir = 0; + } + if (inputState.down) { + newY += walkSpeed; + playerDir = 4; + } + + if (!checkCollisionRect({ playerPos.x, newY }, world)) + { + // can move on the y + finalY = newY; + } + + if (!checkCollisionRect({ newX, playerPos.y }, world)) + { + // can move on the X + finalX = newX; + } + + playerPos.x = finalX; + playerPos.y = finalY; + + camera = playerPos; + + if (enemyWalkTimer > enemyWalkTime) + { + // flip the direction and reset the timer + enemyDirection = !enemyDirection; + enemyWalkTimer = 0; + } + + float enemyWalkSpeed = 0.04; + if (enemyDirection) // true == 1 == going right + { + birdPos.x += enemyWalkSpeed; + } + else // going left + { + birdPos.x -= enemyWalkSpeed; + } + + } + + + static bool forward = true; + if (animCounter >= animTime) + { + animCounter = 0; + + if (forward) + { + playerFrame += 1; + if (playerFrame >= 2) + { + forward = false; + } + } + else + { + playerFrame -= 1; + if (playerFrame <= 0) + { + forward = true; + } + } + } + + SDL_RenderClear(renderer); + { + renderTilemap(world, WORLD_WIDTH, WORLD_HEIGHT, camera); + renderWorld(); + } + SDL_RenderPresent(renderer); + } + else if (gameState == COMBAT) { + runCombat(delta); + } + } + + + for (int i = 0; i < WORLD_HEIGHT; ++i) delete[] world[i]; + delete[] world; + + S2DE::quitRendering(&renderer, &window); + Mix_Quit(); + + SDL_DestroyTexture(environment_sheet); + // destroy the other shit here + // add mix_quit to dll + return 0; } \ No newline at end of file diff --git a/main_menu.cpp b/main_menu.cpp index cc3608f..b821faf 100644 --- a/main_menu.cpp +++ b/main_menu.cpp @@ -1,66 +1,66 @@ -#include "main_menu.h" -#include "globals.h" -#include "ui.h" - -static const char* menuItems[] = { "Overworld", "Combat", "Load Game", "Options", "Quit" }; -static constexpr int numMenuItems = 5; -int currentMenuItem = 0; - - -void renderMainPanel(); - -void renderMainPanel() { - - int panelWidth = 200; - int panelHeight = 150; - - int panelX = WINDOW_WIDTH / 2 - panelWidth / 2; - int panelY = WINDOW_HEIGHT / 2 - panelHeight / 2; - - renderBasicPanel(panelX, panelY, panelWidth, panelHeight); - - int leftPad = 40; - int topPad = 20; - int itemSpacing = 30; - - for (int i = 0; i < numMenuItems; ++i) { - renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, menuItems[i]); - } - - renderString(panelX + 20, panelY + topPad + (itemSpacing * currentMenuItem), ">"); - -} - -void mainMenu(double deltaTime) { - S2DE::updateInputState(&inputState); - - if (inputState.up) { - inputState.up = false; - currentMenuItem--; - if (currentMenuItem < 0) currentMenuItem = numMenuItems - 1; - } - else if (inputState.down) { - inputState.down = false; - currentMenuItem++; - if (currentMenuItem > numMenuItems - 1) currentMenuItem = 0; - } - else if (inputState.rtrn) { - inputState.rtrn = false; - // select the current menu item - switch (currentMenuItem) { - case 0: - gameState = OVERWORLD; - break; - case 1: - gameState = COMBAT; - break; - default: - inputState.quit = true; - break; - } - } - - SDL_RenderClear(renderer); - renderMainPanel(); - SDL_RenderPresent(renderer); +#include "main_menu.h" +#include "globals.h" +#include "ui.h" + +static const char* menuItems[] = { "Overworld", "Combat", "Load Game", "Options", "Quit" }; +static constexpr int numMenuItems = 5; +int currentMenuItem = 0; + + +void renderMainPanel(); + +void renderMainPanel() { + + int panelWidth = 200; + int panelHeight = 150; + + int panelX = WINDOW_WIDTH / 2 - panelWidth / 2; + int panelY = WINDOW_HEIGHT / 2 - panelHeight / 2; + + renderBasicPanel(panelX, panelY, panelWidth, panelHeight); + + int leftPad = 40; + int topPad = 20; + int itemSpacing = 30; + + for (int i = 0; i < numMenuItems; ++i) { + renderString(panelX + leftPad, panelY + topPad + itemSpacing * i, menuItems[i]); + } + + renderString(panelX + 20, panelY + topPad + (itemSpacing * currentMenuItem), ">"); + +} + +void mainMenu(double deltaTime) { + S2DE::updateInputState(&inputState); + + if (inputState.up) { + inputState.up = false; + currentMenuItem--; + if (currentMenuItem < 0) currentMenuItem = numMenuItems - 1; + } + else if (inputState.down) { + inputState.down = false; + currentMenuItem++; + if (currentMenuItem > numMenuItems - 1) currentMenuItem = 0; + } + else if (inputState.rtrn) { + inputState.rtrn = false; + // select the current menu item + switch (currentMenuItem) { + case 0: + gameState = OVERWORLD; + break; + case 1: + gameState = COMBAT; + break; + default: + inputState.quit = true; + break; + } + } + + SDL_RenderClear(renderer); + renderMainPanel(); + SDL_RenderPresent(renderer); } \ No newline at end of file diff --git a/main_menu.h b/main_menu.h index 5e48827..ce1eff3 100644 --- a/main_menu.h +++ b/main_menu.h @@ -1,4 +1,4 @@ -#pragma once - - +#pragma once + + void mainMenu(double deltaTime); \ No newline at end of file diff --git a/tilemap.cpp b/tilemap.cpp index abe76d6..1d505c0 100644 --- a/tilemap.cpp +++ b/tilemap.cpp @@ -1,83 +1,83 @@ -#include "tilemap.h" -#include "globals.h" - - -using json = nlohmann::json; - -void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight) -{ - json jsonData = S2DE::loadJson(mapPath); - - json groundData = jsonData["layers"][0]["data"]; - - for (int y = 0; y < worldHeight; ++y) - { - for (int x = 0; x < worldWidth; ++x) - { - int jsonIdx = (y * worldHeight) + x; - - int groundType = groundData[jsonIdx]; - - bool solid = groundType > 30; // lazy hack - - world[y][x] = { groundType, solid }; - } - } -} - -void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera) -{ - for (int y = 0; y < worldHeight; ++y) - { - for (int x = 0; x < worldWidth; ++x) - { - - float scale = 4; - S2DE::Vec2 worldPos = { x, y }; - SDL_Rect dRect = S2DE::worldToScreenRect(&camera, &worldPos, scale, WINDOW_WIDTH, WINDOW_HEIGHT, 16, 16); - - //if (dRect.x >= 0 && dRect.x + dRect.w <= WINDOW_WIDTH - (16 * scale) && dRect.y >= 0 && dRect.y + dRect.h <= WINDOW_HEIGHT - (16 * scale)) - if (world[y][x].ground != 160 && dRect.x + dRect.w >= 0 && dRect.x <= WINDOW_WIDTH && dRect.y + dRect.h >= 0 && dRect.y <= WINDOW_HEIGHT) - { - - if (world[y][x].ground == 71) - { - // render water animated - - S2DE::Rect waterSRect = { playerFrame * 16, 0, 16, 16 }; - - S2DE::renderTexture(&renderer, &water_test_sheet, &waterSRect, &dRect); - } - else - { - - int tile_idx = world[y][x].ground - 1; - - int sheet_width = 10; - - int tile_x = (tile_idx % sheet_width); - int tile_y = (tile_idx / sheet_width); - - SDL_Rect sRect = { tile_x * 16, tile_y * 16, 16, 16 }; - - - S2DE::renderTexture(&renderer, &environment_sheet, &sRect, &dRect); - } - - } - - } - } -} - -bool checkCollisionRect(S2DE::Vec2 worldPos, WorldCell** world) { - return (world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.25)].solid || - world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.75)].solid || - world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.25)].solid || - world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.75)].solid); - -} - -bool checkCollisionPoint(S2DE::Vec2 worldPos, WorldCell** world) { - return world[(int)worldPos.y][(int)worldPos.x].solid; +#include "tilemap.h" +#include "globals.h" + + +using json = nlohmann::json; + +void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight) +{ + json jsonData = S2DE::loadJson(mapPath); + + json groundData = jsonData["layers"][0]["data"]; + + for (int y = 0; y < worldHeight; ++y) + { + for (int x = 0; x < worldWidth; ++x) + { + int jsonIdx = (y * worldHeight) + x; + + int groundType = groundData[jsonIdx]; + + bool solid = groundType > 30; // lazy hack + + world[y][x] = { groundType, solid }; + } + } +} + +void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera) +{ + for (int y = 0; y < worldHeight; ++y) + { + for (int x = 0; x < worldWidth; ++x) + { + + float scale = 4; + S2DE::Vec2 worldPos = { x, y }; + SDL_Rect dRect = S2DE::worldToScreenRect(&camera, &worldPos, scale, WINDOW_WIDTH, WINDOW_HEIGHT, 16, 16); + + //if (dRect.x >= 0 && dRect.x + dRect.w <= WINDOW_WIDTH - (16 * scale) && dRect.y >= 0 && dRect.y + dRect.h <= WINDOW_HEIGHT - (16 * scale)) + if (world[y][x].ground != 160 && dRect.x + dRect.w >= 0 && dRect.x <= WINDOW_WIDTH && dRect.y + dRect.h >= 0 && dRect.y <= WINDOW_HEIGHT) + { + + if (world[y][x].ground == 71) + { + // render water animated + + S2DE::Rect waterSRect = { playerFrame * 16, 0, 16, 16 }; + + S2DE::renderTexture(&renderer, &water_test_sheet, &waterSRect, &dRect); + } + else + { + + int tile_idx = world[y][x].ground - 1; + + int sheet_width = 10; + + int tile_x = (tile_idx % sheet_width); + int tile_y = (tile_idx / sheet_width); + + SDL_Rect sRect = { tile_x * 16, tile_y * 16, 16, 16 }; + + + S2DE::renderTexture(&renderer, &environment_sheet, &sRect, &dRect); + } + + } + + } + } +} + +bool checkCollisionRect(S2DE::Vec2 worldPos, WorldCell** world) { + return (world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.25)].solid || + world[(int)(worldPos.y + 0.55)][(int)(worldPos.x + 0.75)].solid || + world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.25)].solid || + world[(int)(worldPos.y + 0.95)][(int)(worldPos.x + 0.75)].solid); + +} + +bool checkCollisionPoint(S2DE::Vec2 worldPos, WorldCell** world) { + return world[(int)worldPos.y][(int)worldPos.x].solid; } \ No newline at end of file diff --git a/tilemap.h b/tilemap.h index 8aed93f..fee94ee 100644 --- a/tilemap.h +++ b/tilemap.h @@ -1,18 +1,18 @@ -#pragma once - -#include <2DEngine.h> - -// same here -struct WorldCell -{ - int ground; - bool solid; -}; - - -void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight); - -void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera); - -bool checkCollisionRect(S2DE::Vec2 worldPos, WorldCell** world); +#pragma once + +#include <2DEngine.h> + +// same here +struct WorldCell +{ + int ground; + bool solid; +}; + + +void loadWorld(const char* mapPath, WorldCell** world, int worldWidth, int worldHeight); + +void renderTilemap(WorldCell** world, int worldWidth, int worldHeight, S2DE::Camera camera); + +bool checkCollisionRect(S2DE::Vec2 worldPos, WorldCell** world); bool checkCollisionPoint(S2DE::Vec2 worldPos, WorldCell** world); \ No newline at end of file diff --git a/ui.cpp b/ui.cpp index 80070cd..79e9147 100644 --- a/ui.cpp +++ b/ui.cpp @@ -1,91 +1,91 @@ -#include "ui.h" -#include "globals.h" - - - -static constexpr int panelDrawSize = 16 * 2; - -S2DE::Rect topLeftCorner = { 0, 0, 16, 16 }; -S2DE::Rect topRightCorner = { 32, 0, 16, 16 }; -S2DE::Rect bottomLeftCorner = { 0, 32, 16, 16 }; -S2DE::Rect bottomRightCorner = { 32, 32, 16, 16 }; -S2DE::Rect leftSide = { 0, 16, 16, 1 }; -S2DE::Rect rightSide = { 32, 16, 16, 1 }; -S2DE::Rect topSide = { 16, 0, 1, 16 }; -S2DE::Rect bottomSide = { 16, 32, 1, 16 }; -S2DE::Rect fill = { 10, 10, 1, 1 }; - -S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font) { - // this part should be in DLL - - //SDL_Texture* fontTX = debugFont ? debug_font : font_sheet; - if (!font) { - font = font_sheet; - } - - int glyphWidth = 6; - int glyphHeight = 8; - - int glyphScale = 2; - - S2DE::Rect finalRect = { startX, startY, 0, glyphHeight * glyphScale }; - - int i = 0; - while (string[i] != '\0') - { - int sheetX = (int)string[i] - 32; - - - S2DE::Rect sRect = { sheetX * glyphWidth, 0, glyphWidth, glyphHeight }; - S2DE::Rect dRect = { startX + (i * glyphWidth * glyphScale), startY, glyphWidth * glyphScale, glyphHeight * glyphScale }; - - S2DE::renderTexture(&renderer, &font, &sRect, &dRect); - - i++; - } - - finalRect.w = i * glyphWidth * glyphScale; - - return finalRect; -} - -void renderBasicPanel(int x, int y, int width, int height) { - // smallest supported size? 40? - if (width < 40) width = 40; - if (height < 40) height = 40; - - S2DE::Rect dRect; - - // top left corner - dRect = { x, y, panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &topLeftCorner, &dRect); - - // top right corner - dRect = { x + (width - panelDrawSize), y, panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &topRightCorner, &dRect); - - // bottom left - dRect = { x, y + height - panelDrawSize, panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomLeftCorner, &dRect); - - // bottom right - dRect = { x + width - panelDrawSize, y + height - panelDrawSize, panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomRightCorner, &dRect); - - // sides - dRect = { x, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize}; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &leftSide, &dRect); - - dRect = { x + width - panelDrawSize, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &rightSide, &dRect); - - dRect = { x + panelDrawSize, y, width - 2 * panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &topSide, &dRect); - - dRect = { x + panelDrawSize, y + height - panelDrawSize, width - 2 * panelDrawSize, panelDrawSize }; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomSide, &dRect); - - // fill - dRect = { x + panelDrawSize, y + panelDrawSize, width - 2 * panelDrawSize, height - 2 * panelDrawSize}; - S2DE::renderTexture(&renderer, &ui_frame_sheet, &fill, &dRect); +#include "ui.h" +#include "globals.h" + + + +static constexpr int panelDrawSize = 16 * 2; + +S2DE::Rect topLeftCorner = { 0, 0, 16, 16 }; +S2DE::Rect topRightCorner = { 32, 0, 16, 16 }; +S2DE::Rect bottomLeftCorner = { 0, 32, 16, 16 }; +S2DE::Rect bottomRightCorner = { 32, 32, 16, 16 }; +S2DE::Rect leftSide = { 0, 16, 16, 1 }; +S2DE::Rect rightSide = { 32, 16, 16, 1 }; +S2DE::Rect topSide = { 16, 0, 1, 16 }; +S2DE::Rect bottomSide = { 16, 32, 1, 16 }; +S2DE::Rect fill = { 10, 10, 1, 1 }; + +S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font) { + // this part should be in DLL + + //SDL_Texture* fontTX = debugFont ? debug_font : font_sheet; + if (!font) { + font = font_sheet; + } + + int glyphWidth = 6; + int glyphHeight = 8; + + int glyphScale = 2; + + S2DE::Rect finalRect = { startX, startY, 0, glyphHeight * glyphScale }; + + int i = 0; + while (string[i] != '\0') + { + int sheetX = (int)string[i] - 32; + + + S2DE::Rect sRect = { sheetX * glyphWidth, 0, glyphWidth, glyphHeight }; + S2DE::Rect dRect = { startX + (i * glyphWidth * glyphScale), startY, glyphWidth * glyphScale, glyphHeight * glyphScale }; + + S2DE::renderTexture(&renderer, &font, &sRect, &dRect); + + i++; + } + + finalRect.w = i * glyphWidth * glyphScale; + + return finalRect; +} + +void renderBasicPanel(int x, int y, int width, int height) { + // smallest supported size? 40? + if (width < 40) width = 40; + if (height < 40) height = 40; + + S2DE::Rect dRect; + + // top left corner + dRect = { x, y, panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &topLeftCorner, &dRect); + + // top right corner + dRect = { x + (width - panelDrawSize), y, panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &topRightCorner, &dRect); + + // bottom left + dRect = { x, y + height - panelDrawSize, panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomLeftCorner, &dRect); + + // bottom right + dRect = { x + width - panelDrawSize, y + height - panelDrawSize, panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomRightCorner, &dRect); + + // sides + dRect = { x, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize}; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &leftSide, &dRect); + + dRect = { x + width - panelDrawSize, y + panelDrawSize, panelDrawSize, height - 2 * panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &rightSide, &dRect); + + dRect = { x + panelDrawSize, y, width - 2 * panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &topSide, &dRect); + + dRect = { x + panelDrawSize, y + height - panelDrawSize, width - 2 * panelDrawSize, panelDrawSize }; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &bottomSide, &dRect); + + // fill + dRect = { x + panelDrawSize, y + panelDrawSize, width - 2 * panelDrawSize, height - 2 * panelDrawSize}; + S2DE::renderTexture(&renderer, &ui_frame_sheet, &fill, &dRect); } \ No newline at end of file diff --git a/ui.h b/ui.h index 9ef01bf..dfa3d1c 100644 --- a/ui.h +++ b/ui.h @@ -1,7 +1,7 @@ -#pragma once - -#include <2DEngine.h> - -S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font = nullptr); - +#pragma once + +#include <2DEngine.h> + +S2DE::Rect renderString(int startX, int startY, const char* string, SDL_Texture* font = nullptr); + void renderBasicPanel(int x, int y, int width, int height); \ No newline at end of file -- 2.20.1