package view; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.image.WritableImage; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundImage; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import model.world.Direction; import model.world.Position; import model.world.graphs.Edge; import model.world.graphs.Vertex; import java.util.Collection; import java.util.Set; import Controller.Controller; /** * This class represents the view of the labyrinth * It's a singleton be cause you can get only one view */ public class GameView extends Application { private static GameView instance ;//= new GameView(); // Constantes gaphiques static int WallThickness = 5; static int CellSize = 30; private Color WallColor = Color.DIMGRAY; private Color CellColor = Color.CORNFLOWERBLUE; // Composents graphiques private Pane root; private StackPane holder; private Canvas canvas; // Autres attributs private boolean initialized = false; private GameView() { } public static GameView getInstance() { if (instance == null) instance = new GameView(); return instance; } /** * Draw on the fx Pane the labyrinth, to show it call the method start. * @param cellsX The max x size of the labyrinth * @param cellsY The max y size of the labyrinth * @param edges The wall of the labyrinth * @param d A collection of all entities present on the labyrinth */ public void initializeView(int cellsX, int cellsY, Set edges, Collection d) { assert !initialized : "The view cant be initialized twice"; holder = new StackPane(); holder.setFocusTraversable(true); holder.setOnKeyPressed(Controller.getInstance()); canvas = new Canvas(cellsX * (CellSize + WallThickness) + WallThickness, cellsY * (CellSize + WallThickness) + WallThickness); Background background = new Background(makeBackground(cellsX, cellsY, edges)); holder.setBackground(background); root = new Pane(); holder.getChildren().add(canvas); root.getChildren().add(holder); for(AbsView av : d) root.getChildren().add(av.getImageView()); } /** * @param primaryStage The fx Stage where the Labyrinth will be draw */ public void start(Stage primaryStage) { Scene scene = new Scene(root); primaryStage.setTitle("Assassins creed 5: Labyrinthe"); primaryStage.setScene(scene); primaryStage.show(); } /** * Change the actual BackGround by background * @param background the new backgroun dto display * @param sizeX * @param sizeY */ public void actualizeLevel(Background background, int sizeX, int sizeY) { assert initialized : "The view need to be initialised"; holder.setBackground(background); } /** * Compute the max number of case that the labyrinth can display with size(width and height) given * @param width * @param height * @return */ public static int[] maxSize(int width, int height) { int[] size = new int[2]; // On considère qu'il y a des murs sur l'extérieur size[0] = (width - WallThickness) / (CellSize + WallThickness); size[1] = (height - WallThickness) / (CellSize + WallThickness); return size; } /** * @return Background instance * @author Simmon * @see GameView * @see Color * @since 2017-18-11 * Function to retrieve a 2D represention of the world. This image will be set as * background for the view. * Algorithm explanations: * n x p board, contains (n*p) cells and (n+1)*(p+1) walls * * ◄--------- n = 7 -------► * ╔═══╦═══╦═══╦═══╦═══╦═══╗ ▲ * ║ ║ ║ ║ ║ ║ ║ | * ╠═══╬═══╬═══╬═══╬═══╬═══╣ | * ║ ║ ║ ║ ║ ║ ║ | * ╠═══╬═══╬═══╬═══╬═══╬═══╣ | * ║ ║ ║ ║ ║ ║ ║ p = 6 * ╠═══╬═══╬═══╬═══╬═══╬═══╣ | * ║ ║ ║ ║ ║ ║ ║ | * ╠═══╬═══╬═══╬═══╬═══╬═══╣ | * ║ ║ ║ ║ ║ ║ ║ | * ╚═══╩═══╩═══╩═══╩═══╩═══╝ ▼ * * First, we draw the whole background with Wall's colour for the space between walls * and for the exterior walls. * * Then we iterate over n & p to draw every cell. To know the coordinate of a cell, * we must take into account the wall thickness. The first cell's top left point is * at (x = WallThickness, y = WallThickness). We then add (WallThickness + CellSize) * to determine the next cells' coordinates. * * */ private BackgroundImage makeBackground(int cellX, int cellY, Set edges) { // Initialisation des variables int x, y, i, j; GraphicsContext context = canvas.getGraphicsContext2D(); // Coloration d'arrière plan : par défaut tout est couleur mur context.setFill(WallColor); // La prochaine chose colorée sera de la couleur des murs context.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); // On colore tout // Dessin des cases context.setFill(CellColor); // Itération sur toutes les cases for (i = 0; i < cellX; i++) { for (j = 0; j < cellY; j++) { // voir javadoc x = WallThickness + i * (CellSize + WallThickness); y = WallThickness + j * (CellSize + WallThickness); context.fillRect(x, y, CellSize, CellSize); } } // Itération sur les arrêtes Vertex source, target; for (Edge edge : edges) { source = edge.getSource(); target = edge.getTarget(); /* Deux cas de figure pour une arrête (u, v): * 1. □║□ -> Mur vertical : u.x == v.x. * On se place sur la case la plus à droite, puis on recule de * (ça se simplifie pour revenir à ne pas l'ajouter) * 2. □ * ═ -> Mur horizontal : la même chose, mais renversé. * □ */ if (source.getX() == target.getX()) { i = source.getX(); j = Math.max(source.getY(), target.getY()); x = WallThickness + i * (CellSize + WallThickness); y = j * (CellSize + WallThickness); context.fillRect(x, y, CellSize, WallThickness); } else { i = Math.max(source.getX(), target.getX()); j = target.getY(); x = i * (CellSize + WallThickness); y = WallThickness + j * (CellSize + WallThickness); context.fillRect(x, y, WallThickness, CellSize); } } WritableImage image = canvas.snapshot(null, null); return new BackgroundImage(image, null, null, null, null); } public static void doDeadAlert() { Alert alert = new Alert(AlertType.INFORMATION); alert.setTitle("If you don't know"); alert.setHeaderText("You are dead!"); alert.setContentText("You can type 'r' to restart this labyrinthe!"); alert.show(); } public void update(EntityView entityView, Position pos, Direction direction) { entityView.setPosition(pos); entityView.move(direction); } }