Skip to content
Snippets Groups Projects
Commit 00700142 authored by jez04's avatar jez04
Browse files

feat: :tada: solution

parent 74097949
No related merge requests found
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,15 +29,8 @@ public class App extends Application {
@Override
public void start(Stage primaryStage) {
try {
System.out.println(getClass().getResource("/lab/LochNess.gif"));
// 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);
String css = this.getClass().getResource("/lab/application.css").toExternalForm();
scene.getStylesheets().add(css);
primaryStage.setScene(scene);
this.primaryStage = primaryStage;
switchToMenu();
primaryStage.resizableProperty().set(false);
primaryStage.setTitle("Java 1 - 1th laboratory");
primaryStage.show();
......@@ -42,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();
}
......
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;
}
}
......@@ -7,7 +7,6 @@ import javafx.scene.paint.Color;
public class DrawingThread extends AnimationTimer {
private final Canvas canvas;
private final GraphicsContext gc;
private Scene scene;
private int frameCount = 0;
......@@ -15,10 +14,9 @@ public class DrawingThread extends AnimationTimer {
private long lastTime;
private long lastSecond = 0;
public DrawingThread(Canvas canvas) {
this.canvas = canvas;
public DrawingThread(Canvas canvas, Scene scene) {
this.scene = scene;
this.gc = canvas.getGraphicsContext2D();
scene = new Scene(canvas.getWidth(), canvas.getHeight());
lastTime = System.nanoTime();
}
......@@ -30,6 +28,10 @@ public class DrawingThread extends AnimationTimer {
long timeDelta = now - lastTime;
scene.draw(gc);
scene.simulate(timeDelta);
computeAndShowFps(now, timeDelta);
}
private void computeAndShowFps(long now, long timeDelta) {
long currentSecond = now / 1_000_000_000;
if(lastSecond == currentSecond) {
frameCount ++;
......@@ -45,8 +47,4 @@ public class DrawingThread extends AnimationTimer {
gc.strokeText(Double.toString(1_000_000_000d/timeDelta), 10, 50);
}
public Scene getScene() {
return scene;
}
}
......@@ -4,54 +4,64 @@ 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 Scene scene;
@FXML
private Slider boatPosition;
private DrawingThread timer;
@FXML
private Canvas canvas;
@FXML
private Canvas canvas;
@FXML
private Slider speed;
@FXML
private Slider speed;
@FXML
void changePosition(ActionEvent event) {
timer.getScene().getRock().changePosition();
@FXML
private Label playerName;
}
@FXML
void changePosition(ActionEvent event) {
scene.getRock().changePosition();
@FXML
void initialize() {
assert boatPosition != 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();
}
@FXML
void initialize() {
assert boatPosition != 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'.";
boatPosition.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
timer.getScene().getBoat().setPosInPercentage(newValue.doubleValue());
scene.getBoat().setPosInPercentage(newValue.doubleValue());
}
});
speed.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
timer.getScene().getBackground().setSpeed(newValue.doubleValue());
scene.getBackground().setSpeed(newValue.doubleValue());
}
});
}
}
public void startGame(String name, int numberOfMonsters) {
playerName.setText(name);
scene = new Scene(canvas.getWidth(), canvas.getHeight(), numberOfMonsters);
timer = new DrawingThread(canvas, scene);
timer.start();
}
public void stop() {
timer.stop();
}
}
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);
}
}
......@@ -13,9 +13,9 @@ public class Scene {
private Rock rock;
private Background background;
public Scene(double width, double height) {
public Scene(double width, double height, int numberOfMonsters) {
size = new Dimension2D(width, height);
sceneEntitites = new DrawableSimulable[8];
sceneEntitites = new DrawableSimulable[3+numberOfMonsters];
background = new Background(this);
rock = new Rock(this, new Point2D(300, 300), new Dimension2D(30, 50));
boat = new Boat(this, new Point2D(20, 200));
......
/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */
#changeButton {
-fx-background-image: url("LochNess.gif");
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(0.0,0.0,255.0,0.5);
-fx-background-insets:5.0px;
}
#panel {
-fx-background-image:url("game-background.jpg");
-fx-background-size: stretch;
}
#gamePanel {
-fx-background-color:RGB(0.0,0.0,100.0);
}
#menuPanel {
-fx-background-image:url("lochness-background.jpg");
-fx-background-size: stretch;
}
#playButton {
-fx-background-color: RGBA(0.0,0.0,255.0,0.5);
}
#playButton:hover {
-fx-background-color: RGBA(0.0,0.0,255.0,0.5);
-fx-text-fill: white;
}
.difficultButton .radio{
visibility: hidden;
}
.difficultButton .dot{
-fx-background-color: red;
}
.difficultButton {
-fx-background-color: RGBA(0.0,0.0,100.0,0.8);
-fx-border-color: RGBA(0.0,0.0,100.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(0,0,100,0.9);
-fx-border-color:RGBA(255,255,0,0.9);
}
}
\ No newline at end of file
......@@ -4,12 +4,13 @@
<?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="gamePanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="491.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>
......@@ -32,7 +33,7 @@
</HBox>
</bottom>
<center>
<Canvas fx:id="canvas" height="340.0" width="749.0" BorderPane.alignment="CENTER">
<Canvas fx:id="canvas" height="376.0" width="777.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
......@@ -41,4 +42,7 @@
<left>
<Slider fx:id="boatPosition" blockIncrement="5.0" majorTickUnit="10.0" max="80.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="20.0" minorTickCount="5" orientation="VERTICAL" prefHeight="331.0" prefWidth="38.0" showTickLabels="true" showTickMarks="true" BorderPane.alignment="CENTER" />
</left>
<top>
<Label fx:id="playerName" text="Label" BorderPane.alignment="CENTER" />
</top>
</BorderPane>
src/main/resources/lab/lochness-background.jpg

47.1 KiB

<?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>
......@@ -3,10 +3,20 @@ package jez04.structure.test;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
......@@ -26,20 +36,18 @@ import javafx.fxml.FXML;
class ClassStructureTest {
Set<String> allClasses = getNameOfAllClasses();
@Test
void hasClassWithPropertyWithFxmlAnnotationTest() {
Set<String> names = getNameOfAllClasses();
long annotationCount = 0;
for (String name : names) {
Class<?> c = getClass(name);
annotationCount += countPropertyWithAnnotation(c, ".*", FXML.class);
annotationCount += countMethodWithAnnotation(c, ".*", FXML.class);
void printAllclassesTest() {
System.out.println("=========================================");
System.out.println("All detected classes:");
for (String name : allClasses) {
System.out.println(name);
}
assertTrue(annotationCount >= 2, "Only " + annotationCount + " FXML annotation found. Requred atleast 2!");
System.out.println("=========================================");
}
@Test
void gameControllerExistenceTest() {
classExist("GameController");
......@@ -53,6 +61,11 @@ class ClassStructureTest {
Class<?> c = getClass("GameController");
hasPropertyWithAnnotation(c, ".*", FXML.class);
}
@Test
void countControllersTest() {
assertTrue(countClassesMatches(".*Controller") > 1, "Only one class named .*Controller found");
}
@Test
void gameControllerActionEventTest() {
classExist("GameController");
......@@ -60,27 +73,18 @@ class ClassStructureTest {
hasMethodRegexp(c, ".*", void.class, ActionEvent.class);
}
@Test
void backgroundExistenceTest() {
classExist("Background");
}
@Test
void backgroundExistenceSetAngleTest() {
classExist("Background");
Class<?> c = getClass("Background");
hasMethod(c, "setSpeed");
}
@Test
void backgroundExistenceSetSpeedTest() {
classExist("Background");
Class<?> c = getClass("Background");
hasMethod(c, "setSpeed");
}
private void isInterface(Class<?> c) {
assertTrue(c.isInterface(), c.getName() + " have to be interface.");
}
private long countClassesMatches(String nameRegExp) {
return allClasses.stream().filter(c -> c.matches(nameRegExp)).count();
}
private List<String> getClassesMatches(String nameRegExp) {
return allClasses.stream().filter(c -> c.matches(nameRegExp)).toList();
}
private void classExist(String name) {
assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Interface " + name + " not found");
......@@ -131,22 +135,6 @@ class ClassStructureTest {
"No field " + propertyNameRegexp + " with annotation " + annotation.getName() + " in class "
+ classDef.getName());
}
private long countPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) {
List<Field> fields = Arrays.asList(classDef.getDeclaredFields());
long propeertyFxmlAnnotationCount = fields.stream().filter(f -> f.getName().matches(propertyNameRegexp))
.flatMap(f -> Arrays.asList(
f.getAnnotations()).stream()).map(a -> a.annotationType()).filter(a ->
a.equals(annotation)).count();
return propeertyFxmlAnnotationCount;
}
private long countMethodWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) {
List<Method> methods = Arrays.asList(classDef.getDeclaredMethods());
long methodFxmlAnnotationCount = methods.stream().filter(f -> f.getName().matches(propertyNameRegexp))
.flatMap(m -> Arrays.asList(
m.getAnnotations()).stream()).map(a -> a.annotationType()).filter(a ->
a.equals(annotation)).count();
return methodFxmlAnnotationCount;
}
private void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType) {
List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
......@@ -212,10 +200,13 @@ class ClassStructureTest {
}
private Set<String> getNameOfAllClasses() {
List<String> initClassesName = Arrays.asList("lab.Routines", "lab.App", "lab.DrawingThread");
List<String> initClassesName = new ArrayList<>();
dynamicaliFoundSomeClass(initClassesName);
initClassesName.addAll(List.of("lab.Routines", "lab.App", "lab.DrawingThread"));
for (String className : initClassesName) {
try {
Class.forName(className);
break;
} catch (ClassNotFoundException e) {
System.out.println(String.format("Class '%s' cannot be loaded: %s", className, e.getMessage()));
}
......@@ -228,13 +219,67 @@ class ClassStructureTest {
|| p.getName().startsWith("javassist")) {
continue;
}
System.out.println(p.getName());
Configuration conf = new ConfigurationBuilder().addScanners(Scanners.SubTypes.filterResultsBy(pc -> true))
.forPackages(p.getName());
Reflections reflections = new Reflections(conf);
allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> {
System.out.println(c);
return true;
})));
}
for (String string : allClasses) {
System.out.println(string);
}
return allClasses;
}
}
\ No newline at end of file
private void dynamicaliFoundSomeClass(List<String> initClassesName) {
URL myClassUrl = ClassStructureTest.class.getResource("ClassStructureTest.class");
myClassUrl.getFile();
try {
Path classRoot = Paths.get(myClassUrl.toURI()).getParent().getParent().getParent().getParent();
if("test-classes".equals(classRoot.getFileName().toString())) {
classRoot = classRoot.getParent().resolve("classes");
}
System.out.println("class root: " + classRoot);
final Path classRootFinal = classRoot;
Files.walkFileTree(classRoot, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if(List.of("jez04", "META-INF").contains(dir.getFileName().toString())) {
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("VISIT: " + file);
if("module-info.class".equals(file.getFileName().toString())) {
return FileVisitResult.CONTINUE;
}
if(!file.getFileName().toString().endsWith(".class")) {
return FileVisitResult.CONTINUE;
}
String foundClassName = classRootFinal.relativize(file).toString();
foundClassName = foundClassName.substring(0, foundClassName.length()-6).replace(File.separatorChar, '.');
initClassesName.add(foundClassName);
return FileVisitResult.TERMINATE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment