diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index 9d9bbfb..64a5288 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -4,7 +4,7 @@ import org.toop.app.App; import org.toop.framework.networking.NetworkingClientManager; import org.toop.framework.networking.NetworkingInitializationException; -public class Main { +public final class Main { static void main(String[] args) { initSystems(); App.run(args); diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java index da9a955..1b06df6 100644 --- a/app/src/main/java/org/toop/app/App.java +++ b/app/src/main/java/org/toop/app/App.java @@ -2,18 +2,50 @@ package org.toop.app; import org.toop.app.menu.MainMenu; import org.toop.app.menu.Menu; -import org.toop.app.menu.QuitMenu; import javafx.application.Application; -import javafx.scene.layout.StackPane; +import javafx.geometry.Pos; import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; import javafx.stage.Stage; -public class App extends Application { +public final class App extends Application { private static Stage stage; - private static Scene scene; private static StackPane root; + private static int width; + private static int height; + + private static boolean isQuitting; + + private static class QuitMenu extends Menu { + public QuitMenu() { + final Region background = createBackground("quit_background"); + + final Text sure = createText("Are you sure?"); + + final Button yes = createButton("Yes", () -> { stage.close(); }); + final Button no = createButton("No", () -> { pop(); isQuitting = false; }); + + final HBox buttons = new HBox(50, yes, no); + buttons.setAlignment(Pos.CENTER); + + final VBox box = new VBox(35, sure, buttons); + box.getStyleClass().add("quit_box"); + box.setAlignment(Pos.CENTER); + box.setMaxWidth(350); + box.setMaxHeight(200); + + pane = new StackPane(background, box); + pane.getStylesheets().add(App.class.getResource("/style/quit.css").toExternalForm()); + } + } + public static void run(String[] args) { launch(args); } @@ -21,7 +53,9 @@ public class App extends Application { @Override public void start(Stage stage) throws Exception { final StackPane root = new StackPane(new MainMenu().getPane()); + final Scene scene = new Scene(root); + scene.getStylesheets().add(App.class.getResource("/style/app.css").toExternalForm()); stage.setTitle("pism"); stage.setMinWidth(1080); @@ -29,7 +63,10 @@ public class App extends Application { stage.setOnCloseRequest(event -> { event.consume(); - push(new QuitMenu()); + + if (!isQuitting) { + quitPopup(); + } }); stage.setScene(scene); @@ -38,25 +75,32 @@ public class App extends Application { stage.show(); App.stage = stage; - App.scene = scene; App.root = root; + + App.width = (int)stage.getWidth(); + App.height = (int)stage.getHeight(); + + App.isQuitting = false; + } + + public static void quitPopup() { + isQuitting = true; + push(new QuitMenu()); } public static void activate(Menu menu) { - scene.setRoot(menu.getPane()); + pop(); + push(menu); } public static void push(Menu menu) { - root.getChildren().add(menu.getPane()); + root.getChildren().addLast(menu.getPane()); } public static void pop() { root.getChildren().removeLast(); } - public static void quit() { - stage.close(); - } - - public static StackPane getRoot() { return root; } + public static int getWidth() { return width; } + public static int getHeight() { return height; } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/GameType.java b/app/src/main/java/org/toop/app/GameType.java new file mode 100644 index 0000000..54dd2ad --- /dev/null +++ b/app/src/main/java/org/toop/app/GameType.java @@ -0,0 +1,21 @@ +package org.toop.app; + +public enum GameType { + TICTACTOE, REVERSI; + + public static String toName(GameType type) { + return switch (type) { + case TICTACTOE -> "Tic Tac Toe"; + case REVERSI -> "Reversi"; + }; + } + + public static GameType toType(String name) { + return switch (name) { + case "Tic Tac Toe" -> TICTACTOE; + case "Reversi" -> REVERSI; + + default -> TICTACTOE; + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/menu/GameMenu.java b/app/src/main/java/org/toop/app/menu/GameMenu.java new file mode 100644 index 0000000..3bcc700 --- /dev/null +++ b/app/src/main/java/org/toop/app/menu/GameMenu.java @@ -0,0 +1,22 @@ +package org.toop.app.menu; + +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextField; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import org.toop.app.GameType; + +public class GameMenu extends Menu { + public GameMenu(GameType type) { + final Region background = createBackground(); + + ComboBox selectedGame = new ComboBox<>(); + + TextField serverIpField = new TextField(); + serverIpField.setPromptText("Enter here your server ip address"); + + VBox box = new VBox(selectedGame, serverIpField); + pane = new StackPane(background, box); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/menu/MainMenu.java b/app/src/main/java/org/toop/app/menu/MainMenu.java index d4e1b70..16e6a37 100644 --- a/app/src/main/java/org/toop/app/menu/MainMenu.java +++ b/app/src/main/java/org/toop/app/menu/MainMenu.java @@ -1,31 +1,45 @@ package org.toop.app.menu; +import org.toop.app.App; +import org.toop.app.GameType; +import org.toop.app.screen.TicTacToeScreen; + import javafx.geometry.Pos; import javafx.scene.control.Button; -import javafx.scene.image.ImageView; import javafx.scene.layout.*; public final class MainMenu extends Menu { public MainMenu() { - final ImageView background = new ImageView(); + final Region background = createBackground(); - final Button tictactoe = createButton("Tic Tac Toe", () -> {}); - final Button reversi = createButton("Reversi", () -> {}); - final Button sudoku = createButton("Sudoku", () -> {}); - final Button battleship = createButton("Battleship", () -> {}); - final Button other = createButton("Other", () -> {}); + final Button tictactoe = createButton("Tic Tac Toe", () -> { App.activate(new GameMenu(GameType.TICTACTOE)); }); + final Button reversi = createButton("Reversi", () -> { App.activate(new GameMenu(GameType.REVERSI)); }); - final VBox gamesBox = new VBox(tictactoe, reversi, sudoku, background, other); - gamesBox.setAlignment(Pos.TOP_CENTER); + final VBox gamesBox = new VBox(10, tictactoe, reversi); + gamesBox.setAlignment(Pos.TOP_LEFT); + gamesBox.setPickOnBounds(false); + gamesBox.setTranslateY(50); + gamesBox.setTranslateX(25); - final Button credits = createButton("Credits", () -> {}); - final Button options = createButton("Options", () -> {}); - final Button quit = createButton("Quit", () -> {}); + final Button credits = createButton("Credits", () -> { App.push(new CreditsMenu()); }); + final Button options = createButton("Options", () -> { App.push(new OptionsMenu()); }); + final Button quit = createButton("Quit", () -> { App.quitPopup(); }); - final VBox creditsBox = new VBox(10, credits, options, quit); - creditsBox.setAlignment(Pos.BOTTOM_CENTER); + final VBox controlBox = new VBox(10, credits, options, quit); + controlBox.setAlignment(Pos.BOTTOM_LEFT); + controlBox.setPickOnBounds(false); + controlBox.setTranslateY(-50); + controlBox.setTranslateX(25); - pane = new StackPane(background, grid); - pane.getStylesheets().add(getClass().getResource("/style/main.css").toExternalForm()); + pane = new StackPane(background, gamesBox, controlBox); + + tictactoe.setOnMouseEntered(_ -> { + final TicTacToeScreen screen = new TicTacToeScreen((int)pane.getHeight()); + screen.simulate(1000); + + push(screen.getCanvas()); + }); + + tictactoe.setOnMouseExited(_ -> { pop(); }); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/menu/Menu.java b/app/src/main/java/org/toop/app/menu/Menu.java index fc0627f..a283ef4 100644 --- a/app/src/main/java/org/toop/app/menu/Menu.java +++ b/app/src/main/java/org/toop/app/menu/Menu.java @@ -1,27 +1,55 @@ package org.toop.app.menu; -import org.toop.app.App; - -import javafx.animation.FadeTransition; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.layout.Pane; -import javafx.util.Duration; +import javafx.scene.layout.Region; +import javafx.scene.text.Text; public abstract class Menu { protected Pane pane; public Pane getPane() { return pane; } - public void fadeBackgroundImage(String imagePath, float from, float to, float milliseconds) { - final FadeTransition fade = new FadeTransition(Duration.millis(milliseconds), App.getRoot()); - fade.setFromValue(from); - fade.setToValue(to); - fade.play(); + public void push(Node node) { + pane.getChildren().addLast(node); } - public Button createButton(String text, Runnable runnable) { - final Button button = new Button(text); + public void pop() { + pane.getChildren().removeLast(); + } + + public Region createBackground(String css) { + final Region background = new Region(); + background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE); + background.getStyleClass().add(css); + + return background; + } + + public Region createBackground() { + return createBackground("background"); + } + + public Text createText(String css, String x) { + final Text text = new Text(x); + text.getStyleClass().add(css); + + return text; + } + + public Text createText(String x) { + return createText("text", x); + } + + public Button createButton(String css, String x, Runnable runnable) { + final Button button = new Button(x); button.setOnAction(_ -> runnable.run()); - button.getStyleClass().add("button"); + button.getStyleClass().add(css); + return button; } + + public Button createButton(String x, Runnable runnable) { + return createButton("button", x, runnable); + } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/menu/QuitMenu.java b/app/src/main/java/org/toop/app/menu/QuitMenu.java deleted file mode 100644 index fe359da..0000000 --- a/app/src/main/java/org/toop/app/menu/QuitMenu.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.toop.app.menu; - -import javafx.geometry.Pos; -import javafx.scene.control.Button; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import org.toop.app.App; - -public final class QuitMenu extends Menu { - public QuitMenu() { - final Region background = new Region(); - background.getStyleClass().add("quit-background"); - background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE); - - final Text sure = new Text("Are you sure?"); - sure.getStyleClass().add("quit-text"); - - final Button yes = new Button("Yes"); - yes.getStyleClass().add("quit-button"); - yes.setOnAction(_ -> { - App.quit(); - }); - - final Button no = new Button("No"); - no.getStyleClass().add("quit-button"); - no.setOnAction(_ -> { - App.pop(); - }); - - final HBox buttons = new HBox(10, yes, no); - buttons.setAlignment(Pos.CENTER); - - VBox box = new VBox(43, sure, buttons); - box.setAlignment(Pos.CENTER); - box.getStyleClass().add("quit-box"); - box.setMaxWidth(350); - box.setMaxHeight(200); - - StackPane modalContainer = new StackPane(background, box); - StackPane.setAlignment(box, Pos.CENTER); - - pane = modalContainer; - pane.getStylesheets().add(getClass().getResource("/style/quit.css").toExternalForm()); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/screen/Screen.java b/app/src/main/java/org/toop/app/screen/Screen.java new file mode 100644 index 0000000..8bab32f --- /dev/null +++ b/app/src/main/java/org/toop/app/screen/Screen.java @@ -0,0 +1,71 @@ +package org.toop.app.screen; + +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; + +public abstract class Screen { + protected final class Cell { + public float x; + public float y; + + public float width; + public float height; + + public Cell(float x, float y, float width, float height) { + this.x = x; + this.y = y; + + this.width = width; + this.height = height; + } + + public boolean check(int x, int y) { + return x >= this.x && y >= this.y && x <= this.x + width && y <= this.y + height; + } + } + + protected final Canvas canvas; + protected final GraphicsContext graphics; + + protected final int width; + protected final int height; + + protected final int rowSize; + protected final int columnSize; + + protected final int gapSize; + + protected final Cell[] cells; + + protected Screen(int width, int height, int rowSize, int columnSize, int gapSize) { + final Canvas canvas = new Canvas(width, height); + final GraphicsContext graphics = canvas.getGraphicsContext2D(); + + this.canvas = canvas; + this.graphics = graphics; + + this.width = width; + this.height = height; + + this.rowSize = rowSize; + this.columnSize = columnSize; + + this.gapSize = gapSize; + + cells = new Cell[rowSize * columnSize]; + + final float cellWidth = ((float)width - (rowSize - 1) * gapSize) / rowSize; + final float cellHeight = ((float)height - (columnSize - 1) * gapSize) / rowSize; + + for (int y = 0; y < columnSize; y++) { + final float startY = y * cellHeight + y * gapSize; + + for (int x = 0; x < rowSize; x++) { + final float startX = x * cellWidth + x * gapSize; + cells[y * rowSize + x] = new Cell(startX, startY, cellWidth, cellHeight); + } + } + } + + public Canvas getCanvas() { return canvas; } +} \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/screen/TicTacToeScreen.java b/app/src/main/java/org/toop/app/screen/TicTacToeScreen.java new file mode 100644 index 0000000..6a1e57d --- /dev/null +++ b/app/src/main/java/org/toop/app/screen/TicTacToeScreen.java @@ -0,0 +1,78 @@ +package org.toop.app.screen; + +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.scene.paint.Color; +import javafx.util.Duration; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class TicTacToeScreen extends Screen { + public TicTacToeScreen(int size) { + super(size, size, 3, 3, 10); + + graphics.setFill(Color.CYAN); + + for (int x = 1; x < rowSize; x++) { + graphics.fillRect(cells[x].x - gapSize, 0, gapSize, height - gapSize); + } + + for (int y = 1; y < columnSize; y++) { + graphics.fillRect(0, cells[y * rowSize].y - gapSize, width - gapSize, gapSize); + } + } + + public void placeX(int cell) { + graphics.setFill(Color.WHITE); + graphics.setLineWidth(gapSize); + + final float x = cells[cell].x; + final float y = cells[cell].y; + + final float width = cells[cell].width; + final float height = cells[cell].height; + + graphics.strokeLine(x, y, x + width, y + height); + graphics.strokeLine(x + width, y, x, y + height); + } + + public void placeO(int cell) { + graphics.setFill(Color.WHITE); + graphics.setLineWidth(gapSize); + + final float x = cells[cell].x; + final float y = cells[cell].y; + + final float width = cells[cell].width; + final float height = cells[cell].height; + + graphics.strokeOval(x, y, width, height); + } + + public void simulate(int speedInMilliseconds) { + final Random random = new Random(); + + final List playedCells = new ArrayList<>(); + + final Timeline timeline = new Timeline(new KeyFrame(Duration.millis(speedInMilliseconds), _ ->{ + int cell; + + do { + cell = random.nextInt(cells.length); + } while (playedCells.contains(cell)); + + if (playedCells.size() % 2 == 0) { + placeX(cell); + } else { + placeO(cell); + } + + playedCells.add(cell); + })); + + timeline.setCycleCount(9); + timeline.play(); + } +} \ No newline at end of file diff --git a/app/src/main/resources/image/background.jpg b/app/src/main/resources/image/background.jpg deleted file mode 100644 index 0e5a01f..0000000 Binary files a/app/src/main/resources/image/background.jpg and /dev/null differ diff --git a/app/src/main/resources/image/game/battleship.png b/app/src/main/resources/image/game/battleship.png deleted file mode 100644 index 813893f..0000000 Binary files a/app/src/main/resources/image/game/battleship.png and /dev/null differ diff --git a/app/src/main/resources/image/game/other.png b/app/src/main/resources/image/game/other.png deleted file mode 100644 index 6bd4167..0000000 Binary files a/app/src/main/resources/image/game/other.png and /dev/null differ diff --git a/app/src/main/resources/image/game/reversi.png b/app/src/main/resources/image/game/reversi.png deleted file mode 100644 index bd9252f..0000000 Binary files a/app/src/main/resources/image/game/reversi.png and /dev/null differ diff --git a/app/src/main/resources/image/game/sudoku.png b/app/src/main/resources/image/game/sudoku.png deleted file mode 100644 index ec88234..0000000 Binary files a/app/src/main/resources/image/game/sudoku.png and /dev/null differ diff --git a/app/src/main/resources/image/game/tictactoe.png b/app/src/main/resources/image/game/tictactoe.png deleted file mode 100644 index 2a81e05..0000000 Binary files a/app/src/main/resources/image/game/tictactoe.png and /dev/null differ diff --git a/app/src/main/resources/image/icon.png b/app/src/main/resources/image/icon.png deleted file mode 100644 index d627e6a..0000000 Binary files a/app/src/main/resources/image/icon.png and /dev/null differ diff --git a/app/src/main/resources/image/lowpoly.png b/app/src/main/resources/image/lowpoly.png new file mode 100644 index 0000000..6565080 Binary files /dev/null and b/app/src/main/resources/image/lowpoly.png differ diff --git a/app/src/main/resources/style/app.css b/app/src/main/resources/style/app.css new file mode 100644 index 0000000..d31e450 --- /dev/null +++ b/app/src/main/resources/style/app.css @@ -0,0 +1,37 @@ +.background { + -fx-background-image: url("/image/lowpoly.png"); +} + +.text { + -fx-fill: white; + + -fx-font-family: "Segoe UI", sans-serif; + -fx-font-weight: bold; + -fx-font-size: 24px; +} + +.button, .text-field, .combo-box, .combo-box-popup .list-cell { + -fx-padding: 10 20; + + -fx-background-color: transparent; + -fx-border-color: transparent; +} + +.combo-box-popup .list-view { + -fx-background-color: #1d1d1d; +} + +.text-field { + -fx-text-fill: white; +} + +.button:hover, .text-field:hover, .combo-box:hover, .combo-box-popup .list-cell:hover { + -fx-cursor: hand; + + -fx-effect: dropshadow(gaussian, #00ffff7f, 10, 0.5, 0, 0); + -fx-border-color: white; +} + +.text-field:focused, .combo-box:focused { + -fx-border-color: white; +} \ No newline at end of file diff --git a/app/src/main/resources/style/main.css b/app/src/main/resources/style/main.css deleted file mode 100644 index 99e8087..0000000 --- a/app/src/main/resources/style/main.css +++ /dev/null @@ -1,33 +0,0 @@ -.main-button { - -fx-background-color: transparent; - -fx-background-image: url("card-default.jpg"); /* fallback image */ - -fx-background-size: cover; - -fx-background-position: center; - -fx-pref-width: 250px; - -fx-pref-height: 180px; - -fx-border-radius: 15; - -fx-background-radius: 15; - -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 15, 0.4, 0, 4); - -fx-cursor: hand; - -fx-padding: 0; -} - -.card-label { - -fx-background-color: rgba(0, 0, 0, 0.5); - -fx-font-size: 20px; - -fx-font-weight: bold; - -fx-text-fill: white; - -fx-padding: 10px; - -fx-alignment: top-center; - -fx-background-radius: 15 15 0 0; - -fx-opacity: 0; - -fx-transition: all 0.3s ease; -} - -.main-button:hover { - -fx-effect: dropshadow(gaussian, #00ffff, 15, 0.5, 0, 0); -} - -.main-button:hover .card-label { - -fx-opacity: 1; -} \ No newline at end of file diff --git a/app/src/main/resources/style/quit.css b/app/src/main/resources/style/quit.css index 59c72a3..b99b206 100644 --- a/app/src/main/resources/style/quit.css +++ b/app/src/main/resources/style/quit.css @@ -1,33 +1,8 @@ -.quit-background { +.quit_background { -fx-background-color: rgba(0, 0, 0, 0.6); } -.quit-box { - -fx-background-color: rgba(30, 30, 30, 0.95); +.quit_box { + -fx-background-color: rgba(30, 30, 30, 0.5); -fx-background-radius: 15; - -fx-padding: 30; - -fx-effect: dropshadow(gaussian, black, 20, 0.6, 0, 4); -} - -.quit-text { - -fx-fill: white; - -fx-font-size: 28px; - -fx-font-weight: 600; - -fx-font-family: "Segoe UI", sans-serif; -} - -.quit-button { - -fx-font-size: 16px; - -fx-text-fill: white; - -fx-background-color: transparent; - -fx-border-color: white; - -fx-border-radius: 5; - -fx-padding: 8 20; - -fx-cursor: hand; -} - -.quit-button:hover { - -fx-text-fill: #00ffff; - -fx-border-color: #00ffff; - -fx-effect: dropshadow(gaussian, #00ffff, 8, 0.5, 0, 0); } \ No newline at end of file diff --git a/app/src/main/resources/style/style.css b/app/src/main/resources/style/style.css deleted file mode 100644 index c09d516..0000000 --- a/app/src/main/resources/style/style.css +++ /dev/null @@ -1,20 +0,0 @@ -.root { - -fx-background-color: #2d2d2d; - - -fx-font-size: 28px; - -fx-font-weight: 600; - -fx-font-family: "Segoe UI", sans-serif; -} - -.button { - -fx-background-color: transparent; - -fx-text-fill: white; - -fx-border-color: transparent; - -fx-padding: 10 20; - -fx-cursor: hand; - -fx-effect: null; -} - -.button:hover { - -fx-effect: dropshadow(gaussian, #00ffff, 10, 0.3, 0, 0); -} \ No newline at end of file