mourning-ember / src / main / java / dev / llan / view / game / GameView.java
GameView.java
Raw
package dev.llan.view.game;

import dev.llan.controller.Controller;
import dev.llan.model.GameRecord;
import dev.llan.model.pieces.Entity;
import dev.llan.view.RenderComponent;
import dev.llan.view.GameComponent;
import dev.llan.view.View;
import dev.llan.view.game.map.Direction.*;
import dev.llan.view.game.map.MapView;
import dev.llan.view.game.utilities.UtilitiesView;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;

import static dev.llan.view.game.map.Constants.MAP_PROPORTION;
import static dev.llan.view.game.map.Constants.MARGIN;

public class GameView implements RenderComponent, GameComponent {
  private final HBox box;
  private final StackPane mapContainer;
  private final StackPane utilContainer;
  private final MapView mapView;
  private final UtilitiesView utilView;

  private boolean controlsEnabled;
  private boolean shouldScroll;

  private Scene scene;
  private View view;
  private Controller controller;

  private GameRecord gameRecord;
  private Timeline timeline;

  public GameView(View view, Controller controller, Scene scene, Pane parent) {
    this.scene = scene;
    this.view = view;
    this.controller = controller;
    box = new HBox();

    box.prefWidthProperty().bind(parent.widthProperty());
    box.maxWidthProperty().bind(parent.widthProperty());
    box.minWidthProperty().bind(parent.widthProperty());
    box.prefHeightProperty().bind(parent.heightProperty());
    box.maxHeightProperty().bind(parent.heightProperty());
    box.minHeightProperty().bind(parent.heightProperty());

    mapContainer = new StackPane();
    utilContainer = new StackPane();

    mapView = new MapView(view, controller, mapContainer);
    utilView = new UtilitiesView(view, controller, utilContainer);

    mapContainer.minWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
    mapContainer.prefWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
    mapContainer.maxWidthProperty().bind(box.widthProperty().multiply(MAP_PROPORTION));
    mapContainer.minHeightProperty().bind(box.heightProperty());
    mapContainer.prefHeightProperty().bind(box.heightProperty());
    mapContainer.maxHeightProperty().bind(box.heightProperty());

    utilContainer.minWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
    utilContainer.prefWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
    utilContainer.maxWidthProperty().bind(box.widthProperty().multiply(1 - MAP_PROPORTION));
    utilContainer.minHeightProperty().bind(box.heightProperty());
    utilContainer.prefHeightProperty().bind(box.heightProperty());
    utilContainer.maxHeightProperty().bind(box.heightProperty());

    mapContainer.getChildren().add(mapView.getRoot());
    utilContainer.getChildren().add(utilView.render());
    box.getChildren().add(mapContainer);
    box.getChildren().add(utilContainer);
  }

  public void setScrolling(boolean shouldScroll) {
    this.shouldScroll = shouldScroll;
  }

  public void initHandlers() {
    shouldScroll = true;
    controlsEnabled = true;

    scene.setOnMouseMoved(mouseEvent -> handleMouseMoved(mouseEvent));
    scene.setOnKeyPressed(keyEvent -> handleKeyPress(keyEvent));

    mapView.initListeners(mapContainer);

    timeline = getTimeline();
    timeline.play();
  }

  public void removeHandlers() {
    shouldScroll = false;
    scene.setOnMouseMoved(mouseEvent -> {});
    scene.setOnKeyPressed(keyEvent -> {});

    timeline.stop();
  }

  @Override
  public void updateGameRecord(GameRecord gameRecord) {
    this.gameRecord = gameRecord;
    mapView.updateGameRecord(gameRecord);
    utilView.updateGameRecord(gameRecord);
  }

  public void setControlsEnabled(boolean enabled) {
    this.controlsEnabled = enabled;
  }

  @Override
  public Parent render() {
    return box;
  }

  private void handleMouseMoved(MouseEvent e) {
    if (controlsEnabled && shouldScroll) {
      double x = e.getX();
      double y = e.getY();
      double mapWidth = scene.getWidth();
      double mapHeight = scene.getHeight();

      if (x < MARGIN) {
        mapView.setXScrollDirection(XScrollDirection.LEFT);
      } else if (x > mapWidth - MARGIN && x < mapWidth) {
        mapView.setXScrollDirection(XScrollDirection.RIGHT);
      } else {
        mapView.setXScrollDirection(XScrollDirection.NONE);
      }

      if (y < MARGIN && x < mapWidth) {
        mapView.setYScrollDirection(YScrollDirection.UP);
      } else if (y > mapHeight - MARGIN && x < mapWidth) {
        mapView.setYScrollDirection(YScrollDirection.DOWN);
      } else {
        mapView.setYScrollDirection(YScrollDirection.NONE);
      }
    } else {
      mapView.setXScrollDirection(XScrollDirection.NONE);
      mapView.setYScrollDirection(YScrollDirection.NONE);
    }
  }

  private void handleKeyPress(KeyEvent keyEvent) {
    if(controlsEnabled) {
      KeyCode code = keyEvent.getCode();
      switch (code) {
        case ESCAPE -> {
          if (view.getModalManager().isCollectionModalOn()) {
            view.getModalManager().setCollectionModalOn(false);
          }
          if (view.getModalManager().isCardModalOn()) {
            view.getModalManager().setCardModalOn(false, null);
          }
          if (view.getModalManager().isEntityModalOn()) {
            view.getModalManager().setEntityModalOn(false, null);
          }
          if (view.getModalManager().isEquipmentModalOn()) {
            view.getModalManager().setEquipmentModalOn(false, null);
          }
          if (view.getModalManager().isStatusModalOn()) {
            view.getModalManager().setStatusModalOn(false, null);
          }
          controller.cancelSelectedCard();
        }
        case C -> view.getModalManager().setCollectionModalOn(true);
        case F -> mapView.setViewPoint(gameRecord.getPlayer().getPosition());
      }
      if (gameRecord.getCurrentTurn().isPresent()) {
        Entity currentTurn = gameRecord.getCurrentTurn().get();
        if (currentTurn == gameRecord.getPlayer()) {
          switch (code) {
            case E -> controller.endTurn();
            case W -> controller.waitTurn();
          }
        }
      }
    }
  }

  private Timeline getTimeline() {
    Timeline timeline =
        new Timeline(
            new KeyFrame(
                Duration.millis(20),
                e -> {
                  if (gameRecord != null && controlsEnabled) {
                    mapView.periodic();
                  }
                }));
    timeline.setCycleCount(Animation.INDEFINITE);
    return timeline;
  }
}