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