public void update(float delta) {
    // We draw the elements in order: from top to bottom.
    // so we need to order the array list
    for (SceneLayer layer : layers) layer.update();

    // music delay update
    if (music != null && !music.isPlaying()) {
      boolean initialTime = false;

      if (currentMusicDelay <= initialMusicDelay) initialTime = true;

      currentMusicDelay += delta;

      if (initialTime) {
        if (currentMusicDelay > initialMusicDelay) playMusic();
      } else {
        if (repeatMusicDelay >= 0 && currentMusicDelay > repeatMusicDelay + initialMusicDelay) {
          currentMusicDelay = initialMusicDelay;
          playMusic();
        }
      }
    }

    for (BaseActor a : actors.values()) {
      a.update(delta);
    }

    camera.update(delta);

    if (followActor != null) {
      camera.updatePos(followActor);
    }
  }
  public void addActor(BaseActor actor) {
    actors.put(actor.getId(), actor);
    actor.setScene(this);

    SceneLayer layer = getLayer(actor.getLayer());

    if (layer == null) { // fallback for compatibility
      layer = new SceneLayer();
      layer.setId(actor.getLayer());
      layers.add(layer);
    }

    layer.add(actor);
  }
  /** Returns the actor at the position. */
  public BaseActor getActorAt(float x, float y) {

    for (SceneLayer layer : layers) {

      if (!layer.isVisible()) continue;

      // Obtain actors in reverse (close to camera)
      for (int i = layer.getActors().size() - 1; i >= 0; i--) {
        BaseActor a = layer.getActors().get(i);

        if (a.hit(x, y)) {
          return a;
        }
      }
    }

    return null;
  }
  /**
   * Returns the Interactive actor at the position. The actor must have the interaction property
   * enabled.
   */
  public InteractiveActor getInteractiveActorAt(float x, float y) {

    for (SceneLayer layer : layers) {

      if (!layer.isVisible()) continue;

      // Obtain actors in reverse (close to camera)
      for (int i = layer.getActors().size() - 1; i >= 0; i--) {
        BaseActor a = layer.getActors().get(i);

        if (a instanceof InteractiveActor
            && ((InteractiveActor) a).hasInteraction()
            && a.hit(x, y)) {
          return (InteractiveActor) a;
        }
      }
    }

    return null;
  }
  @SuppressWarnings("unchecked")
  @Override
  public void read(Json json, JsonValue jsonData) {
    layers = json.readValue("layers", ArrayList.class, SceneLayer.class, jsonData);
    id = json.readValue("id", String.class, jsonData);
    state = json.readValue("state", String.class, jsonData);
    verbManager = json.readValue("verbs", VerbManager.class, jsonData);

    actors = json.readValue("actors", HashMap.class, BaseActor.class, jsonData);
    player = json.readValue("player", String.class, jsonData);

    for (BaseActor actor : actors.values()) {
      actor.setScene(this);

      SceneLayer layer = getLayer(actor.getLayer());
      layer.add(actor);
    }

    orderLayersByZIndex();

    backgroundAtlas = json.readValue("backgroundAtlas", String.class, jsonData);
    backgroundRegionId = json.readValue("backgroundRegionId", String.class, jsonData);
    lightMapAtlas = json.readValue("lightMapAtlas", String.class, jsonData);
    lightMapRegionId = json.readValue("lightMapRegionId", String.class, jsonData);

    musicFilename = json.readValue("musicFilename", String.class, jsonData);
    loopMusic = json.readValue("loopMusic", Boolean.class, jsonData);
    initialMusicDelay = json.readValue("initialMusicDelay", Float.class, jsonData);
    repeatMusicDelay = json.readValue("repeatMusicDelay", Float.class, jsonData);

    isPlayingSer = json.readValue("isPlaying", Boolean.class, jsonData);
    musicPosSer = json.readValue("musicPos", Float.class, jsonData);

    camera = json.readValue("camera", SceneCamera.class, jsonData);
    String followActorId = json.readValue("followActor", String.class, jsonData);

    setCameraFollowActor((SpriteActor) actors.get(followActorId));

    depthVector = json.readValue("depthVector", Vector2.class, jsonData);
    polygonalNavGraph = json.readValue("polygonalNavGraph", PolygonalNavGraph.class, jsonData);
  }
  public void removeActor(BaseActor a) {

    if (player != null && a.getId().equals(player)) {
      player = null;
    }

    BaseActor r = actors.remove(a.getId());

    if (r == null) {
      EngineLogger.error("Removing actor from scene: Actor not found");
      return;
    }

    SceneLayer layer = getLayer(a.getLayer());
    layer.getActors().remove(a);

    if (a instanceof ObstacleActor && polygonalNavGraph != null)
      polygonalNavGraph.removeDinamicObstacle(a.getBBox());

    a.setScene(null);
  }
  public void drawBBoxLines(ShapeRenderer renderer) {
    // renderer.begin(ShapeType.Rectangle);
    renderer.begin(ShapeType.Line);

    for (BaseActor a : actors.values()) {
      Polygon p = a.getBBox();

      if (p == null) {
        EngineLogger.error("ERROR DRAWING BBOX FOR: " + a.getId());
      }

      if (a instanceof ObstacleActor) renderer.setColor(OBSTACLE_COLOR);
      else renderer.setColor(ACTOR_BBOX_COLOR);

      renderer.polygon(p.getTransformedVertices());

      // Rectangle r = a.getBBox().getBoundingRectangle();
      // renderer.rect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    }

    if (polygonalNavGraph != null) {
      renderer.setColor(WALKZONE_COLOR);
      renderer.polygon(polygonalNavGraph.getWalkZone().getTransformedVertices());

      // DRAW LINEs OF SIGHT
      renderer.setColor(Color.WHITE);
      ArrayList<NavNodePolygonal> nodes = polygonalNavGraph.getGraphNodes();
      for (NavNodePolygonal n : nodes) {
        for (NavNode n2 : n.neighbors) {
          renderer.line(n.x, n.y, ((NavNodePolygonal) n2).x, ((NavNodePolygonal) n2).y);
        }
      }
    }

    renderer.end();
  }
  /**
   * Obtains the actor at (x,y) with TOLERANCE.
   *
   * <p>Creates a square with size = TOLERANCE and checks:
   *
   * <p>1. if some vertex from the TOLERANCE square is inside an actor bbox 2. if some actor bbox
   * vertex is inside the TOLERANCE square
   */
  public InteractiveActor getInteractiveActorAtWithTolerance(float x, float y, float tolerance) {

    List<SceneLayer> layers = getLayers();

    tmpToleranceRect.x = x - tolerance / 2;
    tmpToleranceRect.y = y - tolerance / 2;
    tmpToleranceRect.width = tolerance;
    tmpToleranceRect.height = tolerance;

    for (SceneLayer layer : layers) {

      if (!layer.isVisible()) continue;

      // Obtain actors in reverse (close to camera)
      for (int l = layer.getActors().size() - 1; l >= 0; l--) {
        BaseActor a = layer.getActors().get(l);

        if (a instanceof InteractiveActor && ((InteractiveActor) a).hasInteraction()) {

          if (a.hit(x, y)
              || a.hit(tmpToleranceRect.x, tmpToleranceRect.y)
              || a.hit(tmpToleranceRect.x + tmpToleranceRect.width, tmpToleranceRect.y)
              || a.hit(tmpToleranceRect.x, tmpToleranceRect.y + tmpToleranceRect.height)
              || a.hit(
                  tmpToleranceRect.x + tmpToleranceRect.width,
                  tmpToleranceRect.y + tmpToleranceRect.height)) return (InteractiveActor) a;

          float[] verts = a.getBBox().getTransformedVertices();
          for (int i = 0; i < verts.length; i += 2) {
            float vx = verts[i];
            float vy = verts[i + 1];

            if (tmpToleranceRect.contains(vx, vy)) return (InteractiveActor) a;
          }
        }
      }
    }

    return null;
  }
 private void setActorsList(Collection<BaseActor> actors) {
   for (BaseActor actor : actors) {
     this.actors.put(actor.getId(), actor);
   }
 }