please update my enemy class to use animation.pde animation manager:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;

enum AnimationState {
    IDLE, WALKING, ATTACKING, DAMAGED, DYING
}

class Enemy {
    float x, y;
    float speed = 1.5;
    int health;
    int maxHealth = 100;
    float respawnTime;
    float respawnTimer = respawnTime;
    List<PVector> path;
    int pathIndex;
    int updatePathInterval = 60; // Update path every 60 frames
    
    int frameCount = 0;
    boolean active;
    
    PImage spriteSheet;
    int spriteWidth = 90;
    int spriteHeight = 90;
    int currentFrame = 0;
    int frameDelay = 5;
    int frameCounter = 0;

    int stateTimer = 0;
    int damagedDuration = 30; // Duration for damaged state in frames
    int dyingDuration = 60; // Duration for dying animation in frames
    
    AnimationState currentState = AnimationState.IDLE;
    HashMap<AnimationState, Animation> animations = new HashMap<>();
    
    Enemy(float respawnTime) {
        this.respawnTime = respawnTime;
        this.maxHealth = 100;
        this.health = maxHealth;

        this.spriteSheet = random(1) < 0.5 ? enemySpriteSheet1 : enemySpriteSheet2;
        animations.put(AnimationState.ATTACKING, new Animation(0, 11, 5, false));
        animations.put(AnimationState.DYING, new Animation(1, 13, 5, false));
        animations.put(AnimationState.DAMAGED, new Animation(2, 4, 5, false));
        animations.put(AnimationState.IDLE, new Animation(3, 8, 5, true));
        animations.put(AnimationState.WALKING, new Animation(4, 10, 5, true));
        
        respawn(); //this takes care of initital position
        
    }
    void update(Tile[][] map) {
        if (!active) {             //downtime after being killed
            respawnTimer -= 1.0 / frameRate;
            if (respawnTimer <= 0) {
                active = true;
                respawn();
                }
            return;
        }

         if (currentState == AnimationState.DAMAGED || currentState == AnimationState.DYING) {
            stateTimer--;
            if (stateTimer <= 0) {
                if (currentState == AnimationState.DYING) {
                    active = false;
                    respawnTimer = respawnTime;
                } else {
                    setState(AnimationState.WALKING);
                }
            }
            // Don't update position or path while in DAMAGED or DYING state
            updateAnimation();
            return;
        }


        if (!isWithinMapBounds(x, y)) {
            PVector safePosition = findSafeSpawnPosition();
            x = safePosition.x;
            y = safePosition.y;
            }
        frameCount++;
        if (frameCount >= updatePathInterval) {
            updatePath(map);
            frameCount = 0;
            }
        if (path!= null && !path.isEmpty()) {
            PVector target = path.get(pathIndex);
            float dx = target.x - x;
            float dy = target.y - y;
            float distance = sqrt(dx * dx + dy * dy);
            
            if (distance < speed) {
                pathIndex++;
                if (pathIndex >= path.size()) {
                    path = null;
                    setState(AnimationState.IDLE);
                }
            } else {
                float ratio = speed / distance;
                x += dx * ratio;
                y += dy * ratio;
                setState(AnimationState.WALKING);
            }
        } else {
            setState(AnimationState.IDLE);
            }
        frameCounter++;

        updateAnimation();
    }
    
       void updateAnimation() {
        frameCounter++;
        if (frameCounter >= frameDelay) {
            frameCounter = 0;
            currentFrame++;
            if (currentFrame >= animations.get(currentState)[1]) {
                currentFrame = 0;
            }
        }
    }

      void setState(AnimationState newState) {
        if (currentState != newState) {
            print("setting state from: " + currentState + " to " + newState);
            currentState = newState;
            currentFrame = 0;
            if (newState == AnimationState.DAMAGED) {
                stateTimer = damagedDuration;
            } else if (newState == AnimationState.DYING) {
                stateTimer = dyingDuration;
            }
        }
    }

    
    void updatePath(Tile[][] map) {
        int startX = floor(x / TILE_SIZE);
        int startY = floor(y / TILE_SIZE);
        int endX = floor(player.x / TILE_SIZE);
        int endY = floor(player.y / TILE_SIZE);
        
        path = aStar(map,startX, startY, endX, endY);
        pathIndex = 0;
        }

    List<PVector> aStar(Tile[][] map, int startX, int startY, int goalX, int goalY) {
        PriorityQueue<Node> openSet = new PriorityQueue<>();
        boolean[][] closedSet = new boolean[map.length][map[0].length];
        Node[][] nodeMap = new Node[map.length][map[0].length];
        
        for (int i = 0; i < map.length; i++) {
            for (int j = 0;j < map[0].length;j++) {
                nodeMap[i][j] = new Node(i, j);
            }
        }

        Node start = nodeMap[startX][startY];
        Node goal = nodeMap[goalX][goalY];
        start.g = 0;
        start.f = heuristic(start, goal);
        
        openSet.add(start);
        
        while(!openSet.isEmpty()) {
            Node current = openSet.poll();
            
            if (current == goal) {
                return reconstructPath(current);
            }
            closedSet[current.x][current.y] = true;
            
             for (int[] dir : new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}) {

                int neighborX = current.x + dir[0];
                int neighborY = current.y + dir[1];

                if (neighborX < 0 || neighborX >= map.length || neighborY < 0 || neighborY >= map[0].length) {
                    continue;
                    }
                if (closedSet[neighborX][neighborY] || map[neighborX][neighborY].type != TileType.EMPTY) {
                    continue;
                    }
                Node neighbor = nodeMap[neighborX][neighborY];
                float tentativeG = current.g + 1;
                
                if (!openSet.contains(neighbor) || tentativeG < neighbor.g) {
                    neighbor.parent = current;
                    neighbor.g = tentativeG;
                    neighbor.f = neighbor.g + heuristic(neighbor, goal);
                    
                    if (!openSet.contains(neighbor)) {
                        openSet.add(neighbor);
                    }
                }
            }
        }
        return null; // No path found
    }
    
    float heuristic(Node a, Node b) {
        return abs(a.x - b.x) + abs(a.y - b.y);
    }
    
    List<PVector> reconstructPath(Node goal) {
        List<PVector> path = new ArrayList<>();
        Node current = goal;
        while(current != null) {
            path.add(new PVector(current.x * TILE_SIZE + TILE_SIZE / 2, current.y * TILE_SIZE + TILE_SIZE / 2));
            current = current.parent;
            }
        Collections.reverse(path);
        return path;
        }
    
    void takeDamage(int damage) {
        health -= damage;
        if (!isAlive()) {
            setState(AnimationState.DYING);
        }
        else {setState(AnimationState.DAMAGED);}
    }
    
    void respawn() {
        active = true;
        health = maxHealth;
        PVector safePosition = findSafeSpawnPosition();
        x = safePosition.x;
        y = safePosition.y;
        currentState = AnimationState.IDLE;
        currentFrame = 0;
        frameCounter = 0;
        frameCount = 0;
        stateTimer = 0;
        path = null;
        pathIndex = 0;
    }
    
    boolean isAlive() {
        return health > 0;
    }
    

     void display() {
        if (!active) return;
        
        int[] animationInfo = animations.get(currentState);
        int rowIndex = animationInfo[0] / 11;  // 11 frames per row
        int colIndex = (animationInfo[0] + currentFrame) % 11;
        
        pushMatrix();
        translate(x, y);
        
        boolean flipHorizontally = currentState == AnimationState.WALKING &&  path != null && !path.isEmpty() &&  path.get(pathIndex).x < x;
        // Flip the sprite horizontally if moving left
        if (flipHorizontally) {
            scale(-1, 1);
        }
        
         image(spriteSheet, -spriteWidth/2, -spriteHeight/2, spriteWidth, spriteHeight, 
              colIndex * spriteWidth, 
              rowIndex * spriteHeight, 
              (colIndex + 1) * spriteWidth, 
              (rowIndex + 1) * spriteHeight);
        
        popMatrix();
        
        // Draw health bar
       if (health < maxHealth && currentState != AnimationState.DYING) {
            drawHealthBar();
        }
    }

    void drawHealthBar() {
        float barWidth = TILE_SIZE;
        float healthRatio = (float)health / maxHealth;
        float barHeight = 5;
        fill(255, 0, 0);
        rect(x - barWidth / 2, y - TILE_SIZE / 2 - 10,barWidth * healthRatio, barHeight);
        noFill();
        }
    }

    class Node implements Comparable<Node> {
    int x, y;
    float g, f;
    Node parent;
    
    Node(int x, int y) {
        this.x = x;
        this.y = y;
        }
    
    @Override 
    public int compareTo(Node other) {
        return Float.compare(this.f, other.f);
    }
}


animation.pde:
class Animation {
    int row;           // The row in the sprite sheet
    int frameCount;    // Total frames in this animation
    int frameDelay;    //controls animation speed
    boolean loop;      // Should the animation loop?

    Animation(int row, int frameCount, int frameDelay, boolean loop) {
        this.row = row;
        this.frameCount = frameCount;
        this.frameDelay = frameDelay;
        this.loop = loop;
    }
}

use it to optimise my animation sprite frame use