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

feat: :tada: solution

parent fc01b326
No related merge requests found
package lab; package lab;
import javafx.animation.AnimationTimer;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Group; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
...@@ -16,31 +15,25 @@ import javafx.stage.WindowEvent; ...@@ -16,31 +15,25 @@ import javafx.stage.WindowEvent;
*/ */
public class App extends Application { public class App extends Application {
private GameController gameController;
public static void main(String[] args) { public static void main(String[] args) {
launch(args); launch(args);
} }
private Canvas canvas;
private AnimationTimer timer;
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
try { try {
// Construct a main window with a canvas. // Construct a main window with a canvas.
Group root = new Group(); FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/lab/gameWindow.fxml"));
canvas = new Canvas(800, 400); Parent root = gameLoader.load();
root.getChildren().add(canvas); GameController gameController = gameLoader.getController();
Scene scene = new Scene(root, 800, 400); Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene); primaryStage.setScene(scene);
primaryStage.resizableProperty().set(false); primaryStage.resizableProperty().set(false);
primaryStage.setTitle("Java 1 - 1th laboratory"); primaryStage.setTitle("Java 1 - 1th laboratory");
primaryStage.show(); primaryStage.show();
// Exit program when main window is closed // Exit program when main window is closed
primaryStage.setOnCloseRequest(this::exitProgram); primaryStage.setOnCloseRequest(this::exitProgram);
timer = new DrawingThread(canvas);
timer.start();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
...@@ -48,7 +41,7 @@ public class App extends Application { ...@@ -48,7 +41,7 @@ public class App extends Application {
@Override @Override
public void stop() throws Exception { public void stop() throws Exception {
timer.stop(); gameController.stop();
super.stop(); super.stop();
} }
......
...@@ -44,4 +44,8 @@ public class Bullet extends WorldEntity implements Collisionable{ ...@@ -44,4 +44,8 @@ public class Bullet extends WorldEntity implements Collisionable{
} }
public void setVelocity(Point2D velocity) {
this.velocity = velocity;
}
} }
...@@ -33,7 +33,7 @@ public class BulletAnimated extends Bullet { ...@@ -33,7 +33,7 @@ public class BulletAnimated extends Bullet {
public void reload() { public void reload() {
position = cannon.getPosition(); position = cannon.getPosition();
velocity = initVelocity; velocity = new Point2D(0, 0);
} }
} }
\ No newline at end of file
...@@ -27,9 +27,18 @@ public class Cannon extends WorldEntity{ ...@@ -27,9 +27,18 @@ public class Cannon extends WorldEntity{
@Override @Override
public void simulate(double deltaT) { public void simulate(double deltaT) {
angle += angleDelta * deltaT; // angle += angleDelta * deltaT;
if (angle >= 0 || angle <= -90) { // if (angle >= 0 || angle <= -90) {
angleDelta = -angleDelta; // angleDelta = -angleDelta;
} // }
} }
public double getAngle() {
return angle;
}
public void setAngle(double angle) {
this.angle = -angle;
}
} }
...@@ -31,4 +31,8 @@ public class DrawingThread extends AnimationTimer { ...@@ -31,4 +31,8 @@ public class DrawingThread extends AnimationTimer {
lastTime = now; lastTime = now;
} }
public World getWorld() {
return world;
}
} }
package lab;
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.Slider;
public class GameController {
@FXML
private Slider angle;
@FXML
private Slider speed;
@FXML
private Canvas canvas;
private DrawingThread timer;
@FXML
void fire(ActionEvent event) {
double angle = timer.getWorld().getCannon().getAngle();
double angleRad = Math.toRadians(angle);
double speedValue = speed.getValue();
timer.getWorld().getBulletAnimated().reload();
Point2D velocity = new Point2D(
Math.cos(angleRad)*speedValue,
Math.sin(angleRad)*speedValue);
timer.getWorld().getBulletAnimated().setVelocity(velocity);
}
@FXML
void initialize() {
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.getWorld().getCannon().setAngle(newValue.doubleValue());
}
});
}
public void stop() {
timer.stop();
}
}
...@@ -12,16 +12,19 @@ public class World { ...@@ -12,16 +12,19 @@ public class World {
private final double height; private final double height;
private DrawableSimulable[] entities; private DrawableSimulable[] entities;
private Cannon cannon;
private BulletAnimated bulletAnimated;
public World(double width, double height) { public World(double width, double height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
entities = new DrawableSimulable[8]; entities = new DrawableSimulable[8];
Cannon cannon = new Cannon(this, new Point2D(0, height - 20), -45); cannon = new Cannon(this, new Point2D(0, height - 20), -45);
bulletAnimated = new BulletAnimated(this, cannon, new Point2D(0, height), new Point2D(50, -80),
new Point2D(0, 9.81));
entities[0] = cannon; entities[0] = cannon;
entities[1] = new Bullet(this, new Point2D(0, height), new Point2D(30, -30), new Point2D(0, 9.81)); entities[1] = new Bullet(this, new Point2D(0, height), new Point2D(30, -30), new Point2D(0, 9.81));
entities[2] = new BulletAnimated(this, cannon, new Point2D(0, height), new Point2D(50, -80), entities[2] = bulletAnimated;
new Point2D(0, 9.81));
for (int i = 3; i < entities.length; i++) { for (int i = 3; i < entities.length; i++) {
entities[i] = new Ufo(this); entities[i] = new Ufo(this);
} }
...@@ -63,4 +66,12 @@ public class World { ...@@ -63,4 +66,12 @@ public class World {
return height; return height;
} }
public Cannon getCannon() {
return cannon;
}
public BulletAnimated getBulletAnimated() {
return bulletAnimated;
}
} }
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.control.Button?>
<?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="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController">
<bottom>
<HBox alignment="TOP_CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<Slider fx:id="angle" majorTickUnit="15.0" max="90.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minorTickCount="5" showTickLabels="true" showTickMarks="true" HBox.hgrow="ALWAYS" />
<Button mnemonicParsing="false" onAction="#fire" style="-fx-background-color: RED;" text="Fire" textAlignment="CENTER">
<font>
<Font name="System Bold" size="24.0" />
</font>
<cursor>
<Cursor fx:constant="CROSSHAIR" />
</cursor>
<opaqueInsets>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</opaqueInsets>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
<Slider fx:id="speed" max="200.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="50.0" minorTickCount="5" showTickLabels="true" showTickMarks="true" value="50.0" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</bottom>
<center>
<Canvas fx:id="canvas" height="287.0" width="582.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
</Canvas>
</center>
</BorderPane>
package jez04.structure.test; package jez04.structure.test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.reflections.Configuration; import org.reflections.Configuration;
import org.reflections.Reflections; import org.reflections.Reflections;
import org.reflections.scanners.Scanners; import org.reflections.scanners.Scanners;
import org.reflections.util.ConfigurationBuilder; import org.reflections.util.ConfigurationBuilder;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Rectangle2D; import javafx.geometry.Rectangle2D;
import javafx.scene.canvas.GraphicsContext;
class ClassStructureTest { class ClassStructureTest {
private static final String drawableSimulableName = "DrawableSimulable";
private static final String collisionableName = "Collisionable";
Set<String> allClasses = getNameOfAllClasses();
@Test @Test
void ufoClassEexistanceTest() { void gameControllerExistenceTest() {
Set<String> allClasses = getNameOfAllClasses(); classExist("GameController");
assertTrue(allClasses.stream().anyMatch(c -> c.endsWith("Ufo")), "Class Ufo not found"); Class<?> c = getClass("GameController");
hasPropertyWithAnnotation(c, ".*", FXML.class);
hasMethodRegexp(c, ".*", void.class, ActionEvent.class);
} }
@Test @Test
void ufoClassPropertiesTest() { void gameControllerFxmlTest() {
Set<String> allClasses = getNameOfAllClasses(); classExist("GameController");
String ufoClassName = allClasses.stream().filter(c -> c.endsWith("Ufo")).findAny().orElse(null); Class<?> c = getClass("GameController");
assertNotNull(ufoClassName, "Class Ufo not found"); hasPropertyWithAnnotation(c, ".*", FXML.class);
try { }
Class<?> ufoClass = Class.forName(ufoClassName); @Test
List<Method> methods = Arrays.asList(ufoClass.getMethods()); void gameControllerActionEventTest() {
assertTrue(methods.stream().anyMatch(m -> m.getName().contains("draw")), "No method draw"); classExist("GameController");
assertTrue(methods.stream().anyMatch(m -> m.getName().contains("simulate")), "No method simulate"); Class<?> c = getClass("GameController");
assertTrue(methods.stream().anyMatch(m -> m.getName().contains("getBoundingBox")), hasMethodRegexp(c, ".*", void.class, ActionEvent.class);
"No method getBoundingBox");
assertTrue(
methods.stream().filter(m -> m.getName().contains("getBoundingBox"))
.anyMatch(m -> m.getReturnType().equals(Rectangle2D.class)),
"Method getBoundingBox not return Rectangle2D");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
@Test @Test
void worldClassPropertyTest() { void cannonExistenceTest() {
Set<String> allClasses = getNameOfAllClasses(); classExist("Cannon");
String ufoClassName = allClasses.stream().filter(c -> c.endsWith("Ufo")).findAny().orElse(null); }
String worldClassName = allClasses.stream().filter(c -> c.endsWith("World")).findAny().orElse(null); @Test
assertNotNull(worldClassName, "Class World not found"); void cannonExistenceSetAngleTest() {
classExist("Cannon");
Class<?> c = getClass("Cannon");
hasMethod(c, "setAngle");
}
private void isInterface(Class<?> c) {
assertTrue(c.isInterface(), c.getName() + " have to be interface.");
}
private void classExist(String name) {
assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Interface " + name + " not found");
}
private Class<?> getClass(String name) {
String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null);
if (className == null) {
Assertions.fail("Class " + name + " not found.");
}
try { try {
Class<?> worldClass = Class.forName(worldClassName); return Class.forName(className);
List<Field> fields = Arrays.asList(worldClass.getDeclaredFields());
Class<?> ufoClass = Class.forName(ufoClassName);
assertTrue(
fields.stream()
.anyMatch(f -> f.getType().isArray() && f.getType().getComponentType().equals(ufoClass)),
"No array of Ufo in World class");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (PrintStream ps = new PrintStream(baos, true)) {
e.printStackTrace(ps);
} catch (Exception e2) {
Assertions.fail(e2.getMessage());
}
String stackTrace = baos.toString();
Assertions.fail("Class " + name + " not found.\n" + stackTrace);
return null;
} }
} }
@Test private void hasProperty(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array) {
void drawingClassExistenceTest() { List<Field> fields = Arrays.asList(classDef.getDeclaredFields());
Set<String> allClasses = getNameOfAllClasses(); assertTrue(fields.stream().anyMatch(f -> {
int detectedClassCount = 0; if (f.getName().matches(propertyNameRegexp)) {
for (String className : allClasses) { if (array) {
try { return f.getType().isArray() && f.getType().getComponentType().equals(type);
Class<?> clazz = Class.forName(className); } else {
List<Constructor<?>> constructorList = Arrays.asList(clazz.getConstructors()); return f.getType().equals(type);
List<Method> methodList = Arrays.asList(clazz.getMethods());
long drawMethodCount = methodList.stream().filter(m -> m.getName().contains("draw")).count();
long simulateMethodCount = methodList.stream().filter(m -> m.getName().contains("sim")).count();
if (!constructorList.isEmpty() && (drawMethodCount > 0 || simulateMethodCount > 0)) {
System.out.println("DETECT:" + className);
detectedClassCount++;
} }
} catch (ClassNotFoundException e) {
System.out.println(String.format("Class '%s' cannot be loaded: %s", className, e.getMessage()));
} }
} return false;
assertTrue(detectedClassCount >= 2, ""); }), "No field " + propertyNameRegexp + " of type " + type.getName() + " (is array " + array + ") in class "
+ classDef.getName());
}
private void hasPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) {
List<Field> fields = Arrays.asList(classDef.getDeclaredFields());
assertTrue(
fields.stream().filter(f -> f.getName().matches(propertyNameRegexp))
.flatMap(f -> Arrays.asList(
f.getAnnotations()).stream()).map(a -> a.annotationType()).anyMatch(a ->
a.equals(annotation)),
"No field " + propertyNameRegexp + " with annotation " + annotation.getName() + " in class "
+ classDef.getName());
}
private void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType) {
List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName);
assertTrue(
methods.stream().filter(m -> m.getName().contains(methodName))
.anyMatch(m -> m.getReturnType().equals(returnType)),
"Method " + methodName + " not return " + returnType.getName());
}
private void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) {
List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName);
assertTrue(
methods.stream().filter(m -> m.getName().contains(methodName))
.filter(m -> m.getReturnType().equals(returnType))
.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
"Method " + methodName + " has no all parrams:"
+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
}
private void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Class<?> returnType, Class<?>... params) {
List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
assertTrue(methods.stream().anyMatch(m -> m.getName().matches(methodNameRegexp)), "No method " + methodNameRegexp);
assertTrue(
methods.stream().filter(m -> m.getName().matches(methodNameRegexp))
.filter(m -> m.getReturnType().equals(returnType))
.anyMatch(m ->
Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
"Method " + methodNameRegexp + " has no all parrams:"
+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
}
private void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName,
Class<?> returnType, Class<?>... params) {
List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName);
assertTrue(
methods.stream().filter(m -> m.getName().contains(methodName))
.filter(m -> m.getReturnType().equals(returnType)
&& (Modifier.isAbstract(m.getModifiers()) == abstractTag)
&& (Modifier.isFinal(m.getModifiers()) == finalTag))
.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
"Method " + methodName + " has no all params:"
+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
}
private void hasImplements(Class<?> clazz, String... interfaceNames) {
List<Class<?>> interfaces = new ArrayList<>();
Arrays.asList(interfaceNames).stream().map(name -> getClass(name)).forEach(c -> interfaces.add(c));
assertTrue(Arrays.asList(clazz.getInterfaces()).containsAll(interfaces), "Class not implements all interfaces:"
+ interfaces.stream().map(Class::getName).collect(Collectors.joining(", ")));
}
private void hasExtends(Class<?> clazz, String parentName) {
Class<?> parent = getClass(parentName);
assertTrue(clazz.getSuperclass().equals(parent),
"Class " + clazz.getName() + " not extends class " + parentName);
}
private void hasMethod(Class<?> interfaceDef, String methodName) {
List<Method> methods = Arrays.asList(interfaceDef.getMethods());
assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName);
} }
private Set<String> getNameOfAllClasses() { private Set<String> getNameOfAllClasses() {
...@@ -110,7 +204,10 @@ class ClassStructureTest { ...@@ -110,7 +204,10 @@ class ClassStructureTest {
Configuration conf = new ConfigurationBuilder().addScanners(Scanners.SubTypes.filterResultsBy(pc -> true)) Configuration conf = new ConfigurationBuilder().addScanners(Scanners.SubTypes.filterResultsBy(pc -> true))
.forPackages(p.getName()); .forPackages(p.getName());
Reflections reflections = new Reflections(conf); Reflections reflections = new Reflections(conf);
allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> true))); allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> {
System.out.println(c);
return true;
})));
} }
return allClasses; return allClasses;
} }
......
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