now can you copy the behaviour of my player system, where I have a sprite sheet for the enemies moves instead of a static image. My enemy sprite sheet is as follows:

there are 5 rows, each row is dedicated to a seperate animation. The first row (11 frames / columns) are the attack frames, second row (13 frames) are the death frames, third row is damage taken (4 frames), fourth row is idle (8 frames) last row (fifth row) is walking animation (10 frames) each frame is 90x90, I will provide the enemy class

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;



    

    AnimationState currentState = AnimationState.IDLE;

    HashMap<AnimationState, int[]> animations = new HashMap<AnimationState, int[]>();

    

    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 int[]{0, 11});

        animations.put(AnimationState.DYING, new int[]{11, 13});

        animations.put(AnimationState.DAMAGED, new int[]{24, 4});

        animations.put(AnimationState.IDLE, new int[]{28, 8});

        animations.put(AnimationState.WALKING, new int[]{36, 9});

        

        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 (!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++;



        if (frameCounter >= frameDelay) {

            frameCounter = 0;

            currentFrame++;

            if (currentFrame >= animations.get(currentState)[1]) {

                if (currentState == AnimationState.DYING) {

                    active = false; 

                } else {

                    currentFrame = 0;

                    }

                }

            }

        }

    

    void setState(AnimationState newState) {

        if (currentState != newState) {

                    print("setting state from: " + currentState +" to " + newState );



            currentState = newState;

            currentFrame = 0;

            }

        }



    

    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);

            

            active = false;

            respawnTimer = respawnTime;

        }

        else {setState(AnimationState.DAMAGED);}

    }

    

    void respawn() {

        active = true;

        health = maxHealth;

        PVector safePosition = findSafeSpawnPosition();

        x = safePosition.x;

        y = safePosition.y;

        }

    

    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);

        

        // Flip the sprite horizontally if moving left

        if (path != null && !path.isEmpty() && path.get(pathIndex).x < x) {

            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) {

            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);

        }

    }