From d15ba60b284af289e216405616805b33e32b43db Mon Sep 17 00:00:00 2001 From: Stan_Lewry Date: Sat, 31 Aug 2024 17:41:19 +0100 Subject: [PATCH] Add very basic attack animation --- combat.cpp | 155 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 47 deletions(-) diff --git a/combat.cpp b/combat.cpp index 6fc0f39..59b2cd9 100644 --- a/combat.cpp +++ b/combat.cpp @@ -27,7 +27,7 @@ struct Character { // how to handle "moves" S2DE::Vec2 combatMoveDestination = { 0.0f, 0.0f }; - int basicAttackRange = 1.5f; + int basicAttackRange = 1.75f; bool canMove = true; bool canAttack = true; @@ -68,6 +68,7 @@ static const double frameTime = 1.0f / 60.0f; SDL_Texture* arrowSprite = nullptr; SDL_Texture* indicatorSprite = nullptr; SDL_Texture* indicatorRedSprite = nullptr; +SDL_Texture* hitAnim = nullptr; static constexpr int arenaWidth = 100; static constexpr int arenaHeight = 100; @@ -310,6 +311,8 @@ void initCombatScene() arrowSprite = S2DE::loadTexture("assets/arrow.png", &renderer); indicatorSprite = S2DE::loadTexture("assets/little_indicator.png", &renderer); indicatorRedSprite = S2DE::loadTexture("assets/little_indicator_red.png", &renderer); + hitAnim = S2DE::loadTexture("assets/hit_anim_1.png", &renderer); + //Character player = { true, "Player", 100, 100, 50, 50, 10.0f, 3.0f, player_sheet, { 23.0f, 13.0f } }; Character player; @@ -405,55 +408,82 @@ void moveToPosition(Character* c, S2DE::Vec2 destination, float 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); + static double animTimer = 0; + double animFramerate = 1.0 / 10.0; + + + frameTimer += delta; + animTimer += delta; + + static int animFrame = 0; + int animFrameSize = 48; + + if (frameTimer > frameTime) { + + frameTimer = 0; + // 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; - currentCombatState = SELECT_TARGET; + default: + inputState.quit = true; + break; } - break; - case 2: // end selected - currentCombatState = TURN_ORDER; - break; - - default: - inputState.quit = true; - break; } } + if (animTimer > animFramerate) { + animTimer = 0; + animFrame += 1; + if (animFrame > 4) animFrame = 0; + } + + + SDL_RenderClear(renderer); renderCombat(); renderUIFull(); + + /*SDL_Rect animDRect = { 0, 0, 96, 96 }; + SDL_Rect animSRect = { 48 * animFrame, 0, 48, 48 }; + S2DE::renderTexture(&renderer, &hitAnim, &animSRect, &animDRect);*/ + SDL_RenderPresent(renderer); } @@ -635,25 +665,56 @@ void selectAttackTarget(double delta) { void doAttack(double delta) { // for now just subtract the combatants' dmg from the targets hp and move on + static int animFrame = 0; + static double animTimer = 0; + static const double animFrameRate = 1.0 / 10.0; + + + animTimer += delta; + + Character* target = targets.at(currentTargetIdx); if (currentTargetIdx == -1) { // AOE, apply to all targets in range ? } else { - Character* target = targets.at(currentTargetIdx); - target->currentHP -= activeCombatant->attack; + + if (animTimer > animFrameRate) { + animTimer = 0; + animFrame += 1; + + if (animFrame > 4) { + // anim is complete, apply damage and move on. + // reset timers etc. + target->currentHP -= activeCombatant->attack; + + if (target->currentHP <= 0) { + target->alive = false; + target->currentHP = 0; + } + - if (target->currentHP <= 0) { - target->alive = false; - target->currentHP = 0; + animFrame = 0; + targets.clear(); + + currentCombatState = ACTION_SELECT; + activeCombatant->canAttack = false; + } } } + + // render the attacking anim + + SDL_RenderClear(renderer); + renderCombat(); + S2DE::Rect animDRect = S2DE::worldToScreenRect(&combatCam, &target->position, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32); + S2DE::Rect animSRect = { 48 * animFrame, 0, 48, 48 }; + S2DE::renderTexture(&renderer, &hitAnim, &animSRect, &animDRect); + renderUIFull(); - targets.clear(); - currentCombatState = ACTION_SELECT; - activeCombatant->canAttack = false; + SDL_RenderPresent(renderer); } -- 2.20.1