diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java index d434fac..74aa52b 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java @@ -53,15 +53,12 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa */ @Override public void onAction(NetworkEvent event) throws RemoteException { - if(event.getIsError()) { - clientController.view.showError(event.toString()); - } else { - synchronized (clientController) - { - event.apply(clientController.miniModel); - } - clientController.view.render(); - - } + synchronized (clientController) { + if(event.getIsError()) { + clientController.view.showError(event.toString()); + } else { + clientController.view.applyAndRender(event); + } + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java index f1b14b3..2b1e3d3 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java @@ -1,7 +1,9 @@ package it.polimi.ingsw.gc14.View.GUI; import it.polimi.ingsw.gc14.Controller.ClientController; +import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.MiniModel; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.View.GUI.LoginFXMLController; import it.polimi.ingsw.gc14.View.GUI.MainFXMLController; import it.polimi.ingsw.gc14.View.IView; @@ -29,9 +31,14 @@ public class GUI extends Application implements IView { FXMLLoader loaderMain; Scene mainScene; MainFXMLController controllerMain; + MiniModel miniModel; + + FXMLLoader loaderLeaderboard; + Scene leaderboardScene; + LeaderboardFXMLController controllerLeaderboard; + private ClientController controller; - private MiniModel model; public GUI(Stage stage) { this.primaryStage = stage; @@ -57,6 +64,12 @@ public class GUI extends Application implements IView { controllerMain.setController(controller); return controllerMain; }); + + loaderLeaderboard = new FXMLLoader(getClass().getResource("/GUIScene/standing.fxml")); + leaderboardScene = new Scene(loaderLeaderboard.load()); + controllerLeaderboard = loaderLeaderboard.getController(); + controllerLeaderboard.setController(controller); + mainScene = new Scene(loaderMain.load()); controllerMain = loaderMain.getController(); @@ -72,30 +85,42 @@ public class GUI extends Application implements IView { @Override public void setModel(MiniModel miniModel) { - this.model=model; + this.miniModel=miniModel; } public void setController(ClientController controller) { this.controller=controller; } + public void applyAndRender(NetworkEvent event) { + Platform.runLater(() -> { + event.apply(miniModel); + if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { + controllerTotem.render(); + primaryStage.setScene(totemScene); + } + else if (controller.miniModel.currentState.getGameStage() == GameStages.ENDED) { + controllerLeaderboard.render(); + primaryStage.setScene(leaderboardScene); + primaryStage.setFullScreen(true); + }else { + controllerMain.render(event); + primaryStage.setScene(mainScene); + } + }); + } + public void render() { - if(controller.miniModel.currentState.getGameStage()==TOTEM_CHOICE) { - Platform.runLater(() -> { - synchronized (this) { - controllerTotem.render(); - primaryStage.setScene(totemScene); - primaryStage.setFullScreen(true); - } - }); + if (!Platform.isFxApplicationThread()) { + Platform.runLater(this::render); + return; + } + if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { + controllerTotem.render(); + primaryStage.setScene(totemScene); } else { - Platform.runLater(() -> { - synchronized (this) { - controllerMain.render(); - primaryStage.setScene(mainScene); - primaryStage.setFullScreen(true); - } - }); + controllerMain.render(); + primaryStage.setScene(mainScene); } } diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java new file mode 100644 index 0000000..564759d --- /dev/null +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java @@ -0,0 +1,356 @@ +package it.polimi.ingsw.gc14.View.GUI; + +import it.polimi.ingsw.gc14.Controller.ClientController; +import it.polimi.ingsw.gc14.Model.Player; +import javafx.animation.ScaleTransition; +import it.polimi.ingsw.gc14.Model.PlayableCard; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.stage.Popup; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.effect.DropShadow; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.*; +import javafx.scene.paint.Color; +import javafx.scene.paint.LinearGradient; +import javafx.scene.paint.Stop; +import javafx.scene.paint.CycleMethod; +import javafx.scene.text.Font; +import javafx.stage.Window; +import javafx.util.Duration; + +import java.util.*; + +public class LeaderboardFXMLController { + + @FXML private StackPane rootPane; + @FXML private VBox mainVBox; + @FXML private VBox rankingList; + // titleLabel rimossa: il testo Winner/GameOver è aggiunto dinamicamente in render() + + private ClientController controller; + + private Popup popup; + private VBox popupContent; + + // Cache condivisa con MainFXMLController + private static final Map imageCache = new HashMap<>(); + + private Image loadImage(String path) { + return imageCache.computeIfAbsent(path, + p -> new Image(getClass().getResourceAsStream(p))); + } + + + public void setController(ClientController controller) { + this.controller = controller; + } + + + @FXML + public void initialize() { + Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); + mainVBox.sceneProperty().addListener((obs, oldScene, newScene) -> { + if (newScene != null) newScene.getRoot().applyCss(); + }); + renderBackground(); + initPopup(); + } + + + public void render() { + rankingList.getChildren().clear(); + + List sorted = controller.miniModel.standingPlayers; + + boolean iWon = sorted.get(0).getUserName().equals(controller.myUsername); + + // Label grande Winner / Game Over + Label outcomeLabel = new Label(iWon ? "\uD83C\uDFC6 WINNER! \uD83C\uDFC6" : "GAME OVER"); + outcomeLabel.setStyle( + "-fx-font-size: 64px;" + + "-fx-font-weight: bold;" + + "-fx-text-fill: " + (iWon ? "#FFD700;" : "#FF4444;") + ); + DropShadow glow = new DropShadow(); + glow.setColor(iWon ? Color.rgb(255, 200, 0, 0.95) : Color.rgb(220, 0, 0, 0.95)); + glow.setRadius(35); + glow.setSpread(0.35); + outcomeLabel.setEffect(glow); + rankingList.getChildren().add(outcomeLabel); + + // Separatore + Region sep = new Region(); + sep.setPrefHeight(16); + rankingList.getChildren().add(sep); + + for (int i = 0; i < sorted.size(); i++) { + rankingList.getChildren().add(createPlayerRow(i + 1, sorted.get(i))); + } + } + + + // ==== EFFECTS ==== + private void addHoverZoom(Node node) { + ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), node); + scaleUp.setToX(1.02); + scaleUp.setToY(1.02); + ScaleTransition scaleDown = new ScaleTransition(Duration.millis(150), node); + scaleDown.setToX(1.0); + scaleDown.setToY(1.0); + node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> { scaleUp.play(); node.setCursor(Cursor.HAND); }); + node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); + } + + private void addShadow(Node node) { + DropShadow shadow = new DropShadow(); + shadow.setColor(Color.rgb(0, 0, 0, 0.6)); + shadow.setRadius(12); + shadow.setOffsetX(3); + shadow.setOffsetY(3); + node.setEffect(shadow); + } + + + // ==== ROW ==== + private HBox createPlayerRow(int position, Player player) { + HBox row = new HBox(20); + row.setAlignment(Pos.CENTER_LEFT); + row.setPadding(new Insets(14, 28, 14, 28)); + row.setMaxWidth(Double.MAX_VALUE); + + // Sfumatura scura semitrasparente come sfondo della riga + LinearGradient gradient = new LinearGradient( + 0, 0, 1, 0, true, CycleMethod.NO_CYCLE, + new Stop(0.0, Color.rgb(0, 0, 0, 0.75)), + new Stop(0.5, Color.rgb(0, 0, 0, 0.60)), + new Stop(1.0, Color.rgb(0, 0, 0, 0.75)) + ); + row.setBackground(new Background(new BackgroundFill( + gradient, + new CornerRadii(12), + Insets.EMPTY + ))); + addShadow(row); + addHoverZoom(row); + + // Posizione medaglia + Label posLabel = new Label(position + "°"); + posLabel.setMinWidth(55); + String medalColor = switch (position) { + case 1 -> "#FFD700"; // oro + case 2 -> "#C0C0C0"; // argento + case 3 -> "#CD7F32"; // bronzo + default -> "#EEEEEE"; + }; + posLabel.setStyle("-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: " + medalColor + ";"); + + + // Totem + ImageView totem = new ImageView(loadImage( + "/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); + totem.setFitHeight(55); + totem.setPreserveRatio(true); + + // Username + Label nameLabel = new Label(player.getUserName()); + nameLabel.setStyle( + "-fx-font-size: 22px; -fx-font-weight: bold; -fx-text-fill: " + + (player.getUserName().equals(controller.myUsername) ? "#ff6b6b;" : "#FFFFFF;") + ); + HBox.setHgrow(nameLabel, Priority.ALWAYS); + + // Statistiche (icona + numero) + HBox stats = createStatsBox(player); + + // Punti prestigio in evidenza a destra + HBox ppBox = new HBox(6); + ppBox.setAlignment(Pos.CENTER); + ImageView ppIcon = new ImageView(loadImage("/GUIImages/Icons/PrestigePoint.png")); + ppIcon.setFitHeight(45); + ppIcon.setPreserveRatio(true); + Label ppLabel = new Label(String.valueOf(player.getPrestigeValue())); + ppLabel.setStyle("-fx-font-size: 28px; -fx-font-weight: bold; -fx-text-fill: #FFD700;"); + ppBox.getChildren().addAll(ppIcon, ppLabel); + + row.getChildren().addAll(posLabel, totem, nameLabel, stats, ppBox); + row.setOnMouseClicked(e -> openPlayerPopup(player)); + return row; + } + + private HBox createStatsBox(Player player) { + HBox stats = new HBox(14); + stats.setAlignment(Pos.CENTER); + + stats.getChildren().add(createStatItem("/GUIImages/Icons/Food.png", String.valueOf(player.getFoodValue()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Artist.png", String.valueOf(player.artists.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Gatherer.png", String.valueOf(player.gatherers.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Inventor.png", String.valueOf(player.inventors.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Builder.png", String.valueOf(player.builders.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Shaman.png", String.valueOf(player.shamans.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Hunter.png", String.valueOf(player.hunters.size()), 26)); + stats.getChildren().add(createStatItem("/GUIImages/Icons/Building.png", String.valueOf(player.buildingCards.size()), 26)); + + return stats; + } + + private HBox createStatItem(String iconPath, String value, double iconHeight) { + HBox box = new HBox(4); + box.setAlignment(Pos.CENTER); + ImageView icon = new ImageView(loadImage(iconPath)); + icon.setFitHeight(iconHeight); + icon.setPreserveRatio(true); + Label label = new Label(value); + label.setStyle("-fx-font-size: 16px; -fx-text-fill: #FFFFFF; -fx-font-weight: bold;"); + // Ombra sul testo per leggibilità extra + DropShadow textShadow = new DropShadow(); + textShadow.setColor(Color.rgb(0, 0, 0, 0.9)); + textShadow.setRadius(4); + label.setEffect(textShadow); + box.getChildren().addAll(icon, label); + return box; + } + + + // ==== POPUP ==== + private void initPopup() { + popupContent = new VBox(12); + popupContent.setAlignment(Pos.CENTER); + popupContent.setPadding(new Insets(16)); + popupContent.setStyle( + "-fx-background-color: rgba(20,10,5,0.97);" + + "-fx-border-color: #8B4513;" + + "-fx-border-width: 3;" + + "-fx-border-radius: 14;" + + "-fx-background-radius: 14;" + ); + + popup = new Popup(); + popup.getContent().add(popupContent); + popup.setAutoHide(true); + popup.addEventHandler(Event.ANY, e -> { + if (popup.getScene() != null) popup.getScene().setFill(Color.TRANSPARENT); + }); + } + + private void openPlayerPopup(Player player) { + popupContent.getChildren().clear(); + + // Intestazione con totem + nome + HBox header = new HBox(10); + header.setAlignment(Pos.CENTER); + ImageView totem = new ImageView(loadImage( + "/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); + totem.setFitHeight(30); + totem.setPreserveRatio(true); + Label nameLabel = new Label(player.getUserName()); + nameLabel.setStyle("-fx-font-size: 18px; -fx-font-weight: bold; -fx-text-fill: #FFD700;"); + header.getChildren().addAll(totem, nameLabel); + popupContent.getChildren().add(header); + + // Tutte le carte in un unico FlowPane, raggruppate per tipo con separatore icona + String[][] types = { + {"Artist", "artists"}, + {"Gatherer", "gatherers"}, + {"Inventor", "inventors"}, + {"Builder", "builders"}, + {"Shaman", "shamans"}, + {"Hunter", "hunters"}, + {"Building", "buildingCards"} + }; + + // Griglia unica: icona tipo | carte... per ogni riga + VBox grid = new VBox(6); + grid.setAlignment(Pos.CENTER_LEFT); + boolean hasAnyCard = false; + + for (String[] type : types) { + String typeName = type[0]; + String field = type[1]; + ArrayList cards = getPlayerCards(player.getUserName(), field); + if (cards.isEmpty()) continue; + hasAnyCard = true; + + HBox row = new HBox(6); + row.setAlignment(Pos.CENTER_LEFT); + + // Icona tipo come intestazione riga + ImageView typeIcon = new ImageView(loadImage("/GUIImages/Icons/"+typeName+".png")); + typeIcon.setFitHeight(22); + typeIcon.setPreserveRatio(true); + row.getChildren().add(typeIcon); + + // Carte piccole in riga + for (PlayableCard card : cards) { + ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png")); + img.setFitHeight(160); + img.setPreserveRatio(true); + // Tooltip al hover: mostra la carta grande in un secondo popup + img.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> img.setFitHeight(180)); + img.addEventHandler(MouseEvent.MOUSE_EXITED, e -> img.setFitHeight(160)); + img.setCursor(Cursor.HAND); + row.getChildren().add(img); + } + + grid.getChildren().add(row); + } + + if (!hasAnyCard) { + Label empty = new Label("Nessuna carta"); + empty.setStyle("-fx-font-size: 14px; -fx-text-fill: #888888;"); + grid.getChildren().add(empty); + } + + grid.setMaxHeight(460); + grid.setMaxWidth(680); + popupContent.getChildren().add(grid); + + Window window = rootPane.getScene().getWindow(); + popup.show(window, 0, 0); + popup.getScene().setFill(Color.TRANSPARENT); + popup.setX(window.getX() + (window.getWidth() - popup.getWidth()) / 2); + popup.setY(window.getY() + (window.getHeight() - popup.getHeight()) / 2); + } + + private ArrayList getPlayerCards(String username, String type) { + Player p = controller.miniModel.players.get(username); + return switch (type) { + case "artists" -> new ArrayList<>(p.artists); + case "gatherers" -> new ArrayList<>(p.gatherers); + case "inventors" -> new ArrayList<>(p.inventors); + case "builders" -> new ArrayList<>(p.builders); + case "shamans" -> new ArrayList<>(p.shamans); + case "hunters" -> new ArrayList<>(p.hunters); + case "buildingCards" -> new ArrayList<>(p.buildingCards); + default -> new ArrayList<>(); + }; + } + + // ==== BACKGROUND ==== + private void renderBackground() { + BackgroundSize size = new BackgroundSize( + BackgroundSize.AUTO, BackgroundSize.AUTO, + false, false, true, true + ); + rootPane.setBackground(new Background(new BackgroundImage( + loadImage("/GUIImages/Background.png"), + BackgroundRepeat.NO_REPEAT, + BackgroundRepeat.NO_REPEAT, + BackgroundPosition.CENTER, + size + ))); + } + + + // ==== ACTIONS ==== + @FXML + private void onNewGame() { + //controller.requestNewGame(); + } +} diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java index ae17de4..35fa593 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java @@ -4,12 +4,11 @@ import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Model.*; import it.polimi.ingsw.gc14.Model.Cards.BuildingCard; import it.polimi.ingsw.gc14.Model.Cards.TribeCard; -import it.polimi.ingsw.gc14.Model.GamePackage.Board; -import it.polimi.ingsw.gc14.Model.GamePackage.CurrentState; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.Orders.OrderPlayer; +import it.polimi.ingsw.gc14.Network.EventType; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import javafx.animation.ScaleTransition; -import javafx.application.Platform; import javafx.event.Event; import javafx.fxml.FXML; import javafx.geometry.Insets; @@ -30,10 +29,6 @@ import javafx.stage.Window; import javafx.util.Duration; import java.util.*; -import java.util.stream.Collectors; - -import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.RES_ACTIONS; -import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.SLOT_CHOICE; public class MainFXMLController { @@ -55,8 +50,14 @@ public class MainFXMLController { private HBox popupCards; private ClientController controller; - private GameStages old_state_stage; - private String old_state_username; + + // ==== IMAGE CACHE ==== + private static final Map imageCache = new HashMap<>(); + + private Image loadImage(String path) { + return imageCache.computeIfAbsent(path, + p -> new Image(getClass().getResourceAsStream(p))); + } public void setController(ClientController controller) { @@ -64,60 +65,41 @@ public class MainFXMLController { } - - @FXML public void initialize() { - old_state_stage=null; - old_state_username=""; - - - // Import font and apply CSS Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> { if (newScene != null) { newScene.getRoot().applyCss(); } }); - - // Initialize popup initPopup(); + renderBackground(); // solo una volta } + // ==== RENDER ==== + public void render() { + renderUpper(); + renderBoard(); + renderLower(); + renderMyHand(); + renderSidePanel(); + } - public synchronized void render() { - if (old_state_stage==null) { - renderBackground(); - renderUpper(); + public void render(NetworkEvent event) { + if (event.getEventType() == EventType.SLOT_CHOICE) { renderBoard(); - renderLower(); - renderMyHand(); - renderSidePanel(); - } else if (old_state_stage==SLOT_CHOICE ) { - System.out.println("OLD: "+old_state_stage+", NEW: "+controller.miniModel.currentState.getGameStage()); - System.out.println("RIDISEGNO BOARD\n"); - renderBoard(); - } else if (old_state_stage==RES_ACTIONS) { - System.out.println("OLD: "+old_state_stage+", NEW: "+controller.miniModel.currentState.getGameStage()); - System.out.println("RIDISEGNO TUTTO. USERNAME: "+old_state_username); + } else { renderUpper(); renderBoard(); renderLower(); renderSidePanel(); - if (Objects.equals(old_state_username, controller.myUsername)) { + if (Objects.equals(event.getUsername(), controller.myUsername) + || event.getEventType() == EventType.NEXT_ROUND) { renderMyHand(); } - - // TODO: se sono io a pescare renderizzo myHand, altrimenti no (non è scontato) - } else { - System.out.println("NON GESTITO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } - - old_state_stage=controller.miniModel.currentState.getGameStage(); - old_state_username=controller.miniModel.currentState.getCurrentPlayer().getUserName(); - // TODO: le info in sidepanel non vengono aggiornate sempre aggiornate, bisogna prima capire dove metterle - } @@ -130,6 +112,7 @@ public class MainFXMLController { clip.setArcHeight(20); node.setClip(clip); } + private void addHoverZoom(Node node) { ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), node); scaleUp.setToX(1.1); @@ -138,8 +121,9 @@ public class MainFXMLController { scaleDown.setToX(1.0); scaleDown.setToY(1.0); node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> { scaleUp.play(); node.setCursor(Cursor.HAND); }); - node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); + node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); } + private void addShadow(Node node) { DropShadow shadow = new DropShadow(); shadow.setColor(Color.rgb(0, 0, 0, 0.3)); @@ -164,23 +148,23 @@ public class MainFXMLController { // ==== ELEMENTS ==== private StackPane createOrder(String num) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Orders/order-" + num + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Orders/order-" + num + ".png")); img.setFitHeight(240); img.setPreserveRatio(true); addClip(img); - StackPane wrapper = new StackPane(img); - return wrapper; + return new StackPane(img); } + private StackPane createSlot(Slot slot, boolean withZoom, boolean withShadow) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png")); img.setFitHeight(240); img.setPreserveRatio(true); addClip(img); StackPane wrapper = new StackPane(img); Player player = controller.miniModel.slotPlayerMap.get(slot); - if (player != null && controller.miniModel.getPositionByUsername(player.getUserName())!=-1) { - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + if (player != null && controller.miniModel.getPositionByUsername(player.getUserName()) != -1) { + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(70); totem.setPreserveRatio(true); StackPane.setAlignment(totem, Pos.TOP_LEFT); @@ -188,32 +172,23 @@ public class MainFXMLController { wrapper.getChildren().add(totem); } - if (withShadow) { - addShadow(wrapper); - } - if (withZoom) { - addHoverZoom(wrapper); - } + if (withShadow) addShadow(wrapper); + if (withZoom) addHoverZoom(wrapper); return wrapper; } + private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow) { - String id = card.getIdIMG(); - ImageView img; - img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + id + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png")); img.setFitHeight(200); img.setPreserveRatio(true); addClip(img); - StackPane wrapper = new StackPane(img); - if (withShadow) { - addShadow(wrapper); - } - if (withZoom) { - addHoverZoom(wrapper); - } + if (withShadow) addShadow(wrapper); + if (withZoom) addHoverZoom(wrapper); return wrapper; } + private void renderIcons(HBox iconsRow1, HBox iconsRow2, Player player) { String[][] iconTypes = { {"Artist", "artists"}, @@ -232,7 +207,7 @@ public class MainFXMLController { icon.setFitWidth(28); icon.setFitHeight(28); icon.setPreserveRatio(true); - icon.setImage(new Image(getClass().getResourceAsStream("/GUIImages/Icons/" + iconName + ".png"))); + icon.setImage(loadImage("/GUIImages/Icons/" + iconName + ".png")); ArrayList cards = getPlayerCards(player.getUserName(), fieldName); if (cards.isEmpty()) { @@ -248,6 +223,7 @@ public class MainFXMLController { else iconsRow2.getChildren().add(icon); } } + private ArrayList getPlayerCards(String username, String type) { Player p = controller.miniModel.players.get(username); return switch (type) { @@ -268,59 +244,55 @@ public class MainFXMLController { upperList.setAlignment(Pos.CENTER); upperList.getChildren().clear(); - //synchronized (controller) - //{ - int i = 0; - for (TribeCard card : controller.miniModel.board.upperListTribe) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawUpperTribeCard(controller.myUsername, index)); - upperList.getChildren().add(img); - i++; - } - i = 0; - for (BuildingCard card : controller.miniModel.board.upperListBuilding) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawUpperBuildingCard(controller.myUsername, index)); - upperList.getChildren().add(img); - i++; - } - //} + int i = 0; + for (TribeCard card : controller.miniModel.board.upperListTribe) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawUpperTribeCard(controller.myUsername, index)); + upperList.getChildren().add(img); + i++; + } + i = 0; + for (BuildingCard card : controller.miniModel.board.upperListBuilding) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawUpperBuildingCard(controller.myUsername, index)); + upperList.getChildren().add(img); + i++; + } } + private void renderLower() { lowerList.setSpacing(14); lowerList.setAlignment(Pos.CENTER); lowerList.getChildren().clear(); - //synchronized (controller) - //{ - int i = 0; - for (TribeCard card : controller.miniModel.board.lowerListTribe) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawLowerTribeCard(controller.myUsername, index)); - lowerList.getChildren().add(img); - i++; - } - i = 0; - for (BuildingCard card : controller.miniModel.board.lowerListBuilding) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawLowerBuildingCard(controller.myUsername, index)); - lowerList.getChildren().add(img); - i++; - } - //} - } - private void renderDeck() { - String path = ""; - switch (controller.miniModel.currentState.getEra()) { - case 1 -> path = "/GUIImages/Backs/back-001.png"; - case 2 -> path = "/GUIImages/Backs/back-030.png"; - case 3 -> path = "/GUIImages/Backs/back-058.png"; + int i = 0; + for (TribeCard card : controller.miniModel.board.lowerListTribe) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawLowerTribeCard(controller.myUsername, index)); + lowerList.getChildren().add(img); + i++; } - ImageView back = new ImageView(new Image(getClass().getResourceAsStream(path))); + i = 0; + for (BuildingCard card : controller.miniModel.board.lowerListBuilding) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawLowerBuildingCard(controller.myUsername, index)); + lowerList.getChildren().add(img); + i++; + } + } + + private void renderDeck() { + String path = switch (controller.miniModel.currentState.getEra()) { + case 1 -> "/GUIImages/Backs/back-001.png"; + case 2 -> "/GUIImages/Backs/back-030.png"; + case 3 -> "/GUIImages/Backs/back-058.png"; + default -> "/GUIImages/Backs/back-001.png"; + }; + ImageView back = new ImageView(loadImage(path)); back.setFitHeight(240); back.setPreserveRatio(true); addClip(back); @@ -328,6 +300,7 @@ public class MainFXMLController { addHoverZoom(back); board.getChildren().add(back); } + private void renderOrder() { StackPane card = createOrder(Integer.toString(controller.miniModel.players.size())); @@ -337,10 +310,10 @@ public class MainFXMLController { StackPane.setMargin(overlay, new Insets(9, 0, 0, 57)); for (OrderPlayer player : controller.miniModel.orderLogicCard.playerList) { - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(70); totem.setPreserveRatio(true); - if(controller.miniModel.slotPlayerMap.containsValue(player.player)) { + if (controller.miniModel.slotPlayerMap.containsValue(player.player)) { totem.setOpacity(0.5); } overlay.getChildren().add(totem); @@ -348,6 +321,7 @@ public class MainFXMLController { card.getChildren().add(overlay); board.getChildren().add(card); } + private void renderSlotMap() { int i = 0; for (Map.Entry entry : controller.miniModel.slotPlayerMap.entrySet()) { @@ -359,6 +333,7 @@ public class MainFXMLController { i++; } } + private void drawMyHandList(ArrayList cardList) { if (!cardList.isEmpty()) { StackPane img = createCard(cardList.getLast(), true, true); @@ -378,6 +353,7 @@ public class MainFXMLController { myHand.getChildren().add(placeholder); } } + private void renderPlayer(Player player) { VBox card = new VBox(3); VBox.setMargin(card, new Insets(5)); @@ -386,10 +362,10 @@ public class MainFXMLController { addHoverZoom(card); addShadow(card); - // Riga 1: icona totem + nome + // Riga 1: totem + nome HBox headerRow = new HBox(8); headerRow.setAlignment(Pos.CENTER); - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(20); totem.setPreserveRatio(true); Label usernameLabel = new Label(player.getUserName()); @@ -405,7 +381,7 @@ public class MainFXMLController { HBox foodBox = new HBox(4); foodBox.setAlignment(Pos.CENTER); - ImageView foodIcon = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Icons/Food.png"))); + ImageView foodIcon = new ImageView(loadImage("/GUIImages/Icons/Food.png")); foodIcon.setFitHeight(20); foodIcon.setPreserveRatio(true); Label foodLabel = new Label(String.valueOf(player.getFoodValue())); @@ -414,7 +390,7 @@ public class MainFXMLController { HBox prestigeBox = new HBox(1); prestigeBox.setAlignment(Pos.CENTER); - ImageView PPIcon = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Icons/PrestigePoint.png"))); + ImageView PPIcon = new ImageView(loadImage("/GUIImages/Icons/PrestigePoint.png")); PPIcon.setFitHeight(35); PPIcon.setPreserveRatio(true); Label prestigeLabel = new Label(String.valueOf(player.getPrestigeValue())); @@ -423,12 +399,12 @@ public class MainFXMLController { statsRow.getChildren().addAll(foodBox, prestigeBox); - // Righe 3-4: icone carte (3 per riga) + // Righe 3-4: icone carte HBox iconsRow1 = new HBox(6); iconsRow1.setAlignment(Pos.CENTER); HBox iconsRow2 = new HBox(6); iconsRow2.setAlignment(Pos.CENTER); - renderIcons(iconsRow1, iconsRow2, player); // vedi sotto + renderIcons(iconsRow1, iconsRow2, player); card.getChildren().addAll(headerRow, statsRow, iconsRow1, iconsRow2); sidePanel.getChildren().add(card); @@ -442,13 +418,14 @@ public class MainFXMLController { false, false, true, true ); mainHBox.setBackground(new Background(new BackgroundImage( - new Image(getClass().getResourceAsStream("/GUIImages/Background.png")), + loadImage("/GUIImages/Background.png"), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, size ))); } + private void renderBoard() { board.setSpacing(14); board.setAlignment(Pos.CENTER); @@ -457,19 +434,22 @@ public class MainFXMLController { renderOrder(); renderSlotMap(); } + private void renderMyHand() { myHand.getChildren().clear(); myHand.setSpacing(14); myHand.setAlignment(Pos.CENTER); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).artists); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).gatherers); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).inventors); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).builders); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).shamans); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).hunters); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).buildingCards); + Player me = controller.miniModel.players.get(controller.myUsername); + drawMyHandList(me.artists); + drawMyHandList(me.gatherers); + drawMyHandList(me.inventors); + drawMyHandList(me.builders); + drawMyHandList(me.shamans); + drawMyHandList(me.hunters); + drawMyHandList(me.buildingCards); } + private void renderSidePanel() { sidePanel.getChildren().clear(); sidePanel.setSpacing(6); @@ -486,15 +466,7 @@ public class MainFXMLController { } - - - - - - - - - // POPUP + // ==== POPUP ==== private void initPopup() { popupCards = new HBox(10); popupCards.setAlignment(Pos.CENTER); @@ -507,29 +479,29 @@ public class MainFXMLController { "-fx-background-radius: 10;" ); - addClip(popupCards); - popup = new Popup(); popup.getContent().add(popupCards); popup.setAutoHide(true); - // Aspetta che la scena del popup esista, poi la rendi trasparente popup.addEventHandler(Event.ANY, e -> { if (popup.getScene() != null) { popup.getScene().setFill(Color.TRANSPARENT); } }); } + private void openPopup(ArrayList cardList) { popupCards.getChildren().clear(); for (PlayableCard card : cardList) { - StackPane img = createCard(card, false, false); - popupCards.getChildren().add(img); + popupCards.getChildren().add(createCard(card, false, false)); } - Window window = myHand.getScene().getWindow(); - popup.show(window, (window.getWidth() - popup.getWidth()) / 2, (window.getHeight() - popup.getHeight()) / 2); - // La scena esiste solo dopo show() + Window window = myHand.getScene().getWindow(); + popup.show(window, 0, 0); popup.getScene().setFill(Color.TRANSPARENT); + + // centra dopo show() quando le dimensioni sono disponibili + popup.setX(window.getX() + (window.getWidth() - popup.getWidth()) / 2); + popup.setY(window.getY() + (window.getHeight() - popup.getHeight()) / 2); } -} +} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/View/IView.java b/src/main/java/it/polimi/ingsw/gc14/View/IView.java index dc0aaa4..f10b639 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/IView.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/IView.java @@ -7,6 +7,7 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent; public interface IView { public void setModel(MiniModel miniModel); public void render(); + public void applyAndRender(NetworkEvent event); public void showMessage(String message); public void showError(String message); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java index deed706..b463966 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java @@ -1,6 +1,7 @@ package it.polimi.ingsw.gc14.View.TUI; import it.polimi.ingsw.gc14.Model.*; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.View.IView; import java.util.ArrayList; @@ -58,6 +59,10 @@ public class TUI implements IView { this.model = model; this.username = ""; } + public void applyAndRender(NetworkEvent event) { + event.apply(model); + render(); + } /** * Sets the username of the local player. diff --git a/src/main/resources/GUIImages/Icons/Building.png b/src/main/resources/GUIImages/Icons/Building.png new file mode 100644 index 0000000..b140952 Binary files /dev/null and b/src/main/resources/GUIImages/Icons/Building.png differ diff --git a/src/main/resources/GUIScene/standing.fxml b/src/main/resources/GUIScene/standing.fxml new file mode 100644 index 0000000..de0ffa8 --- /dev/null +++ b/src/main/resources/GUIScene/standing.fxml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + +