Enemy Spritesheet Animation not working

Hi I have an Animating Main Character but my Enemy Sprite does Animate but it renders and just freezes in one frame.

#ifndef ENEMY_H
#define ENEMY_H

#include <string>
#include <SDL.h>

// Forward declaration
class Sprite;

class Enemy {
public:
    Enemy(int health, const std::string& spritePath);
    virtual ~Enemy();

    virtual int calculateDamage(int turn) = 0;

    int getHealth() const { return health; }
    void takeDamage(int damage) { health -= damage; }

    void initSprite(SDL_Renderer* renderer);
    void updateAnimation(float deltaTime);
    void render(int x, int y, int width, int height);

    // Animation control methods
    void setFrameRate(float rate);
    void setupDefaultAnimation();

    Sprite* getSprite() { return sprite; }

protected:
    int health;
    std::string spritePath;
    Sprite* sprite;

    // Animation parameters
    int frameWidth;
    int frameHeight;
    int numFrames;
    float frameRate;
    float frameTimer;
    int currentFrame;
};

class EnemyA : public Enemy {
public:
    EnemyA();
    int calculateDamage(int turn) override;
};

class EnemyB : public Enemy {
public:
    EnemyB();
    int calculateDamage(int turn) override;
};

class EnemyC : public Enemy {
public:
    EnemyC();
    int calculateDamage(int turn) override;
};

#endif // ENEMY_H
#include "Enemy.h"
#include "Sprite.h"
#include <stdio.h>
#include <cstdlib>

// Animation frame definitions
#define TZ_H (512 / 4) // Width of a single frame (128px)
#define TZ_V (252 / 2) // Height of a single frame (126px)

Enemy::Enemy(int health, const std::string& spritePath)
    : health(health), spritePath(spritePath), sprite(nullptr),
    frameWidth(0), frameHeight(0), numFrames(0),
    frameRate(0.1f), frameTimer(0.0f), currentFrame(0) {
}

Enemy::~Enemy() {
    if (sprite) {
        delete sprite;
    }
}

void Enemy::setupDefaultAnimation() {
    frameWidth = TZ_H;
    frameHeight = TZ_V;
    numFrames = 8; // Assuming 4 columns x 2 rows
    frameRate = 0.1f; // Default frame rate (10 FPS)
}

void Enemy::setFrameRate(float rate) {
    frameRate = rate;
}

void Enemy::initSprite(SDL_Renderer* renderer) {
    sprite = new Sprite(renderer, spritePath.c_str());
    if (!sprite->loadTexture()) {
        fprintf(stderr, "Failed to load enemy sprite: %s\n", spritePath.c_str());
        delete sprite;
        sprite = nullptr;
        return;
    }
    setupDefaultAnimation();
    if (sprite) {
        sprite->setAnimationParameters(frameWidth, frameHeight, numFrames, frameRate);
    }
}

void Enemy::updateAnimation(float deltaTime) {
    frameTimer += deltaTime;
    while (frameTimer >= frameRate) {
        currentFrame = (currentFrame + 1) % numFrames;
        frameTimer -= frameRate;
    }

    if (sprite) {
        sprite->updateAnimation(deltaTime);
    }
}

void Enemy::render(int x, int y, int width, int height) {
    if (sprite) {
        sprite->render(x, y, width, height);
    }
}

// EnemyA implementation
EnemyA::EnemyA() : Enemy(30, "assets/Sprites/Enemies/enemy1.png") {}

int EnemyA::calculateDamage(int turn) {
    return rand() % 6 + 1;
}

// EnemyB implementation
EnemyB::EnemyB() : Enemy(25, "assets/Sprites/Enemies/enemy2.png") {}

int EnemyB::calculateDamage(int turn) {
    return turn * 2;
}

// EnemyC implementation
EnemyC::EnemyC() : Enemy(25, "assets/Sprites/Enemies/enemy3.png") {}

int EnemyC::calculateDamage(int turn) {
    return (rand() % 6 + 1);
}
//In Combat.cpp
    // Create appropriate enemy type
    switch (level) {
    case 1: currentEnemy = new EnemyA(); break;
    case 2: currentEnemy = new EnemyB(); break;
    case 3: currentEnemy = new EnemyC(); break;
    default: currentEnemy = new EnemyA(); break;
    }

    // Initialize enemy sprite if renderer is available
    if (currentEnemy && renderer) {
        currentEnemy->initSprite(renderer);
    }
}

// Render the combat UI
extern "C" void renderCombat(CombatContext* context) {
    if (currentEnemy == nullptr) {
        SDL_Log("Error: currentEnemy is nullptr");
        return;
    }

    //DestroyTexture code
    // Render enemy sprite aligned with Knight at Y = 400
    if (currentEnemy && currentEnemy->getSprite()) {
        const int knightYBase = 400; // Knight's Y position
        int enemyX, enemyY, enemyWidth, enemyHeight;

        switch (currentLevel) {
        case 1:
            enemyX = 1500;
            enemyWidth = 200;
            enemyHeight = 300;
            enemyY = SCREEN_HEIGHT - 300;
            break;
        case 2:
            enemyX = 1500;
            enemyWidth = 250;
            enemyHeight = 350;
            enemyY = SCREEN_HEIGHT - 300;
            break;
        case 3:
            enemyX = 1500;
            enemyWidth = 300;
            enemyHeight = 400;
            enemyY = SCREEN_HEIGHT - 300;
            break;
        default:
            enemyX = 1500;
            enemyWidth = 200;
            enemyHeight = 300;
            enemyY = SCREEN_HEIGHT - 300;
        }

        currentEnemy->getSprite()->render(enemyX, enemyY, enemyWidth, enemyHeight);
    }

    //other code

Game Download

#ifndef SPRITE_H
#define SPRITE_H

#include <SDL.h>
#include <string>

// Animation frame definitions
#define TZ_H (512 / 4) // Width of a single frame (128px)
#define TZ_V (252 / 2) // Height of a single frame (126px)

class Sprite {
public:
    Sprite(SDL_Renderer* renderer, const std::string& filePath);
    ~Sprite();

    bool loadTexture();
    void render(int x, int y);
    void updateAnimation(float 
    );
    void setSize(int width, int height);
    int getWidth() const;
    int getHeight() const;

    SDL_Texture* getTexture() const;
    void destroyTexture();
    void render(int x, int y, int renderWidth = -1, int renderHeight = -1);

    // Method to set the frame rate dynamically
    void setFrameRate(float rate);

    // Method to set animation parameters
    void setAnimationParameters(int frameW, int frameH, int frames, float rate);

    // Quick setup for standard animations
    void setupDefaultAnimation();

private:
    SDL_Renderer* renderer;
    SDL_Texture* texture;
    std::string filePath;
    int width;
    int height;
    int frameWidth;
    int frameHeight;
    int numFrames;
    float frameTimer;
    float frameRate;
    int currentFrame;
};

#endif // SPRITE_H
#include "Sprite.h"
#include <SDL_image.h>
#include <stdio.h>

Sprite::Sprite(SDL_Renderer* renderer, const std::string& filePath)
    : renderer(renderer), texture(nullptr), filePath(filePath),
    width(0), height(0), frameWidth(0), frameHeight(0),
    numFrames(0), frameTimer(0.0f), frameRate(0.1f), currentFrame(0) {
}

Sprite::~Sprite() {
    if (texture) {
        SDL_DestroyTexture(texture);
    }
}

bool Sprite::loadTexture() {
    SDL_Surface* surface = IMG_Load(filePath.c_str());
    if (!surface) {
        fprintf(stderr, "Failed to load image %s: %s\n", filePath.c_str(), IMG_GetError());
        return false;
    }

    texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);

    if (!texture) {
        fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
        return false;
    }

    SDL_QueryTexture(texture, nullptr, nullptr, &width, &height);
    return true;
}

void Sprite::setAnimationParameters(int frameW, int frameH, int frames, float rate) {
    frameWidth = frameW;
    frameHeight = frameH;
    numFrames = frames;
    frameRate = rate;
}

void Sprite::render(int x, int y, int renderWidth, int renderHeight) {
    if (!texture) {
        fprintf(stderr, "Texture not loaded for sprite: %s\n", filePath.c_str());
        return;
    }

    // Calculate source rectangle based on current frame
    SDL_Rect srcRect = {
        (currentFrame % (width / frameWidth)) * frameWidth,
        (currentFrame / (width / frameWidth)) * frameHeight,
        frameWidth,
        frameHeight
   

Have you debugged your code and checked that the frameTimer variable is actually updated properly?
Print out the variable to the console amd check its value.

You might want to check- and print out the srcRect variable to the console too, to make sure it’s set properly.

You really need to start debugging your code whenever there’s some problem with it.