diff --git a/.gitignore b/.gitignore index db44c8a723e017349e18633821c8ee475d15621c..0878793f51e797274e4a9ebcde5e8e57f57ed014 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .settings/ .project .classpath +.idea/ diff --git a/src/main/java/lab/App.java b/src/main/java/lab/App.java index 735a8b46f274cea82e92e2aa1445583b12e8eb00..9a2c2db85648a36072ae4149a7d08ed00c682f31 100644 --- a/src/main/java/lab/App.java +++ b/src/main/java/lab/App.java @@ -1,5 +1,8 @@ package lab; +import java.io.IOException; +import java.net.URL; + import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -16,6 +19,9 @@ import javafx.stage.WindowEvent; public class App extends Application { private GameController gameController; + + private Stage primaryStage; + public static void main(String[] args) { launch(args); } @@ -23,12 +29,8 @@ public class App extends Application { @Override public void start(Stage primaryStage) { try { - // Construct a main window with a canvas. - FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/lab/gameWindow.fxml")); - Parent root = gameLoader.load(); - GameController gameController = gameLoader.getController(); - Scene scene = new Scene(root); - primaryStage.setScene(scene); + this.primaryStage = primaryStage; + switchToMenu(); primaryStage.resizableProperty().set(false); primaryStage.setTitle("Java 1 - 1th laboratory"); primaryStage.show(); @@ -39,9 +41,34 @@ public class App extends Application { } } + public void switchToGame(String name, int numberOfMonsters) throws IOException { + // Construct a main window with a canvas. + FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/lab/gameWindow.fxml")); + Parent root = gameLoader.load(); + gameController = gameLoader.getController(); + Scene scene = new Scene(root); + URL cssUrl = getClass().getResource("application.css"); + scene.getStylesheets().add(cssUrl.toString()); + primaryStage.setScene(scene); + gameController.startGame(name, numberOfMonsters); + } + private void switchToMenu() throws IOException { + // Construct a main window with a canvas. + FXMLLoader menuLoader = new FXMLLoader(getClass().getResource("/lab/mainScreen.fxml")); + Parent root = menuLoader.load(); + MainScreenController menuController = menuLoader.getController(); + menuController.setApp(this); + Scene scene = new Scene(root); + URL cssUrl = getClass().getResource("application.css"); + scene.getStylesheets().add(cssUrl.toString()); + primaryStage.setScene(scene); + } + @Override public void stop() throws Exception { - gameController.stop(); + if(gameController != null) { + gameController.stop(); + } super.stop(); } diff --git a/src/main/java/lab/Difficult.java b/src/main/java/lab/Difficult.java new file mode 100644 index 0000000000000000000000000000000000000000..6186f2776225b25fed0029b5a39512e3ea6d8149 --- /dev/null +++ b/src/main/java/lab/Difficult.java @@ -0,0 +1,16 @@ +package lab; + +public enum Difficult { + EASY(2), MEDIUM(5), HARD(10); + + private final int numberOfMonsters; + + private Difficult(int numberOfMonsters) { + this.numberOfMonsters = numberOfMonsters; + } + + public int getNumberOfMonsters() { + return numberOfMonsters; + } + +} diff --git a/src/main/java/lab/DrawingThread.java b/src/main/java/lab/DrawingThread.java index a0a63edcc76a220b086fd5dfbe55a8e493a910e3..f32c4a6985d4d017d0dd818b8dd5ad7b57c8d26c 100644 --- a/src/main/java/lab/DrawingThread.java +++ b/src/main/java/lab/DrawingThread.java @@ -6,15 +6,13 @@ import javafx.scene.canvas.GraphicsContext; public class DrawingThread extends AnimationTimer { - private final Canvas canvas; private final GraphicsContext gc; private Level level; private long lastTime; - public DrawingThread(Canvas canvas) { - this.canvas = canvas; + public DrawingThread(Canvas canvas, Level level) { + this.level = level; this.gc = canvas.getGraphicsContext2D(); - this.level = new Level(canvas.getWidth(), canvas.getHeight()); lastTime = System.nanoTime(); } @@ -28,8 +26,4 @@ public class DrawingThread extends AnimationTimer { lastTime = now; } - public Level getLevel() { - return level; - } - } diff --git a/src/main/java/lab/GameController.java b/src/main/java/lab/GameController.java index 6d2f4a68c0fd38dd48256bd97d10080b9accf44b..595ea3489a30cb4408f7ae82315ae11a703f4aa2 100644 --- a/src/main/java/lab/GameController.java +++ b/src/main/java/lab/GameController.java @@ -1,29 +1,34 @@ package lab; +import javafx.animation.AnimationTimer; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.geometry.Point2D; import javafx.scene.canvas.Canvas; +import javafx.scene.control.Label; import javafx.scene.control.Slider; public class GameController { + private AnimationTimer timer; + private Level level; + @FXML private Slider angle; - - private DrawingThread timer; - + @FXML private Canvas canvas; @FXML private Slider speed; + @FXML + private Label playerName; + @FXML void spawn(ActionEvent event) { - timer.getLevel().getPlayer().spawn(); + level.getPlayer().spawn(); } @@ -32,26 +37,31 @@ public class GameController { assert angle != null : "fx:id=\"angle\" was not injected: check your FXML file 'gameWindow.fxml'."; assert canvas != null : "fx:id=\"canvas\" was not injected: check your FXML file 'gameWindow.fxml'."; assert speed != null : "fx:id=\"speed\" was not injected: check your FXML file 'gameWindow.fxml'."; - timer = new DrawingThread(canvas); - timer.start(); angle.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { - timer.getLevel().getPlayer().setAngle(newValue.doubleValue()); + level.getPlayer().setAngle(newValue.doubleValue()); } }); speed.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { - timer.getLevel().getPlayer().setSpeed(newValue.doubleValue()); + level.getPlayer().setSpeed(newValue.doubleValue()); } }); } + public void startGame(String name, int numberOfMonsters) { + playerName.setText(name); + level = new Level(canvas.getWidth(), canvas.getHeight(), numberOfMonsters); + timer = new DrawingThread(canvas, level); + timer.start(); + + } + public void stop() { timer.stop(); } - } diff --git a/src/main/java/lab/Level.java b/src/main/java/lab/Level.java index e5497d23432219adf92c622989a93812108d5f32..07e610b747dd130b9a7525ce677fbd740c0b4b1e 100644 --- a/src/main/java/lab/Level.java +++ b/src/main/java/lab/Level.java @@ -12,11 +12,11 @@ public class Level { private DrawableSimulable[] entities; private Player player; - public Level(double width, double height) { + public Level(double width, double height, int monsterCount) { this.width = width; this.height = height; player = new Player(this, new Point2D(20, 250), new Point2D(100, -20)); - entities = new DrawableSimulable[9]; + entities = new DrawableSimulable[monsterCount+4]; entities[0] = new NicerObstacle(this, new Point2D(20, 150)); entities[1] = new Obstacle(this, new Point2D(300, 200), new Dimension2D(80, 40)); entities[2] = new Obstacle(this); diff --git a/src/main/java/lab/MainScreenController.java b/src/main/java/lab/MainScreenController.java new file mode 100644 index 0000000000000000000000000000000000000000..0dec5be7b1aa951966086b353c060841bab53d4d --- /dev/null +++ b/src/main/java/lab/MainScreenController.java @@ -0,0 +1,53 @@ +package lab; + +import java.io.IOException; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.RadioButton; +import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; + +/** + * + */ +public class MainScreenController { + + @FXML + private ToggleGroup difficult; + + @FXML + private ToggleButton easy; + + @FXML + private ToggleButton hard; + + @FXML + private ToggleButton medium; + + @FXML + private TextField name; + + private App app; + + @FXML + void play(ActionEvent event) throws IOException { + Difficult dif = (Difficult)difficult.getSelectedToggle().getProperties().get(Difficult.class); + app.switchToGame(name.getText(), dif.getNumberOfMonsters()); + } + + public void setApp(App app) { + this.app = app; + } + + @FXML + void initialize() { + assert difficult != null : "fx:id=\"difficult\" was not injected: check your FXML file 'mainScreen.fxml'."; + assert name != null : "fx:id=\"name\" was not injected: check your FXML file 'mainScreen.fxml'."; + easy.getProperties().put(Difficult.class, Difficult.EASY); + medium.getProperties().put(Difficult.class, Difficult.MEDIUM); + hard.getProperties().put(Difficult.class, Difficult.HARD); + } + +} diff --git a/src/main/java/lab/Monster.java b/src/main/java/lab/Monster.java index 9c4cf34979afdae517461e55371771d050a57cd6..220473a0e4f2e105156aff882bc42635cbe0a6d0 100644 --- a/src/main/java/lab/Monster.java +++ b/src/main/java/lab/Monster.java @@ -38,6 +38,9 @@ public class Monster extends WorldEntity implements Collisionable { public void simulate(double delay) { position = position.add(speed.multiply(delay / 1_000_000_000)); position = new Point2D(position.getX(), position.getY() % level.getHeight()); + if(position.getY() + image.getHeight() < 0) { + position = new Point2D(position.getX(), level.getHeight()); + } } @Override diff --git a/src/main/java/lab/Player.java b/src/main/java/lab/Player.java index dd51953dc6ba03b42203e879e5b8a6ac96196435..7bbb0706164176e454fff3b329d2d1c1bc4efa03 100644 --- a/src/main/java/lab/Player.java +++ b/src/main/java/lab/Player.java @@ -12,7 +12,7 @@ import javafx.scene.transform.Rotate; public class Player extends WorldEntity implements Collisionable { private static final Random RANDOM = new Random(); private Point2D speed; - private double speedSize; + private double speedSize = 50; private double angle; public Player(Level level, Point2D position, Point2D speed) { diff --git a/src/main/resources/lab/application.css b/src/main/resources/lab/application.css index 83d6f3343843c65d5dfaf3fedb97b6494c19113d..1200dd30a392b1587d148c7d5e19f09f65beda77 100644 --- a/src/main/resources/lab/application.css +++ b/src/main/resources/lab/application.css @@ -1 +1,61 @@ -/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ \ No newline at end of file +/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ + +Label { + -fx-font-size: 20.0px; + -fx-padding: 10.0px; + -fx-text-fill: white; + -fx-font-weight: 900; +} + +#name{ + -fx-font-weight: 900; + -fx-font-size: 20.0px; + -fx-padding: 10.0px; + -fx-background-color: RGBA(255.0,0.0,0.0,0.5); + -fx-background-insets:5.0px; +} +#panel { + -fx-background-image:url("game-background.jpg"); + -fx-background-size: stretch; +} + +#menuPanel { + -fx-background-image:url("red-monster-menu-background.jpg"); + -fx-background-size: stretch; +} + +#playButton { + -fx-background-color: RGBA(255.0,0.0,0.0,0.5); +} +#playButton:hover { + -fx-background-color: RGBA(255.0,0.0,0.0,0.5); + -fx-text-fill: white; +} + +.difficultButton .radio{ + visibility: hidden; +} +.difficultButton .dot{ + -fx-background-color: red; +} + +.difficultButton { + -fx-background-color: RGBA(100.0,0.0,0.0,0.8); + -fx-border-color: RGBA(100.0,0.0,0.0,0.8); + -fx-border-width:3px; + -fx-border-radius:30.0px; + -fx-text-fill: white; + -fx-font-size: 20.0px; + -fx-background-radius:30.0px; +} + +.difficultButton:hover{ + -fx-effect: dropshadow(gaussian, rgba(255, 255, 0, 0.7), 50.0, 0.7, 0.0, 0.0); + -fx-background-color : RGBA(50,0,0,0.8); +} + +.difficultButton:selected{ + -fx-background-color : RGBA(100,0,0,0.9); + -fx-border-color:RGBA(255,255,0,0.9); +} + diff --git a/src/main/resources/lab/game-background.jpg b/src/main/resources/lab/game-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b662570826bdee752266809798a1495767728cfa Binary files /dev/null and b/src/main/resources/lab/game-background.jpg differ diff --git a/src/main/resources/lab/gameWindow.fxml b/src/main/resources/lab/gameWindow.fxml index 55d798a6be852770de8550ce0b785dd141b9fe39..91a80e63eed85a4395b66a28bb92e15d14934d66 100644 --- a/src/main/resources/lab/gameWindow.fxml +++ b/src/main/resources/lab/gameWindow.fxml @@ -4,17 +4,18 @@ <?import javafx.scene.Cursor?> <?import javafx.scene.canvas.Canvas?> <?import javafx.scene.control.Button?> +<?import javafx.scene.control.Label?> <?import javafx.scene.control.Slider?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.text.Font?> -<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="459.0" prefWidth="824.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController"> +<BorderPane fx:id="panel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="459.0" prefWidth="824.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController"> <bottom> <HBox alignment="TOP_CENTER" prefHeight="66.0" prefWidth="824.0" BorderPane.alignment="CENTER"> <children> - <Slider fx:id="speed" majorTickUnit="15.0" max="200.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="50.0" minorTickCount="5" prefHeight="68.0" prefWidth="736.0" showTickLabels="true" showTickMarks="true" HBox.hgrow="ALWAYS" /> - <Button maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#spawn" prefHeight="46.0" prefWidth="147.0" style="-fx-background-color: blue;" text="Spawn" textAlignment="CENTER" textFill="WHITE" textOverrun="CLIP"> + <Slider fx:id="speed" majorTickUnit="15.0" max="200.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="50.0" minorTickCount="5" prefHeight="68.0" prefWidth="736.0" showTickLabels="true" showTickMarks="true" value="50.0" HBox.hgrow="ALWAYS" /> + <Button maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#spawn" prefHeight="46.0" prefWidth="147.0" style="-fx-background-image: url("https://swi.cs.vsb.cz/dam/jcr:95f56bef-2d5f-44f6-a091-9b81fa065128/LochNess.gif");" text="Spawn" textAlignment="CENTER" textFill="WHITE" textOverrun="CLIP"> <font> <Font name="System Bold" size="22.0" /> </font> @@ -39,6 +40,9 @@ </Canvas> </center> <left> - <Slider fx:id="angle" blockIncrement="25.0" majorTickUnit="30.0" max="360.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minorTickCount="5" orientation="VERTICAL" showTickLabels="true" showTickMarks="true" BorderPane.alignment="CENTER" /> + <Slider fx:id="angle" blockIncrement="25.0" majorTickUnit="30.0" max="360.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minorTickCount="5" orientation="VERTICAL" showTickLabels="true" showTickMarks="true" value="300.0" BorderPane.alignment="CENTER" /> </left> + <top> + <Label fx:id="playerName" text="Label" textAlignment="CENTER" BorderPane.alignment="CENTER" /> + </top> </BorderPane> diff --git a/src/main/resources/lab/mainScreen.fxml b/src/main/resources/lab/mainScreen.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4f2bc2fa0f4c22443a8f5dc1ba6daaeac0f3bcf9 --- /dev/null +++ b/src/main/resources/lab/mainScreen.fxml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.RadioButton?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.control.ToggleGroup?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.text.Font?> + +<BorderPane fx:id="menuPanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.MainScreenController"> + <top> + <HBox prefWidth="200.0" BorderPane.alignment="CENTER"> + <children> + <Label text="Player name:" /> + <TextField fx:id="name" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" promptText="type player name like Java Duke" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + </top> + <bottom> + <Button fx:id="playButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#play" text="Play" BorderPane.alignment="CENTER"> + <font> + <Font name="System Bold" size="51.0" /> + </font></Button> + </bottom> + <center> + <HBox prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER"> + <children> + <RadioButton fx:id="easy" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" styleClass="difficultButton" text="Easy" HBox.hgrow="ALWAYS"> + <toggleGroup> + <ToggleGroup fx:id="difficult" /> + </toggleGroup> + <HBox.margin> + <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> + </HBox.margin> + </RadioButton> + <RadioButton fx:id="medium" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" selected="true" styleClass="difficultButton" text="Medium" toggleGroup="$difficult" HBox.hgrow="ALWAYS"> + <HBox.margin> + <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> + </HBox.margin> + </RadioButton> + <RadioButton fx:id="hard" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" styleClass="difficultButton" text="Hard" toggleGroup="$difficult" HBox.hgrow="ALWAYS"> + <HBox.margin> + <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> + </HBox.margin> + </RadioButton> + </children> + </HBox> + </center> +</BorderPane> diff --git a/src/main/resources/lab/red-monster-menu-background.jpg b/src/main/resources/lab/red-monster-menu-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7c27240ca60fe08213d1e0ac71ab1db2330f114 Binary files /dev/null and b/src/main/resources/lab/red-monster-menu-background.jpg differ