diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 11e0b0117..5c3699dc2 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -14,16 +14,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch source code - uses: actions/checkout@v3.2.0 + uses: actions/checkout@v4.2.2 - name: Set up JDK 21 - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v4.5.0 with: distribution: 'zulu' java-version: 21 - name: Cache Maven packages - uses: actions/cache@v3.0.11 + uses: actions/cache@v4.1.2 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 1afddd034..0f6bd02d7 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -14,16 +14,16 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v3.2.0 + - uses: actions/checkout@v4.2.2 - name: Set up JDK 21 - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v4.5.0 with: distribution: 'zulu' java-version: 21 - name: Cache Maven packages - uses: actions/cache@v3.0.11 + uses: actions/cache@v4.1.2 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69dae0b62..1365cd45a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,10 +17,10 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.2.0 + - uses: actions/checkout@v4.2.2 - name: Set up JDK 21 - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v4.5.0 with: distribution: 'zulu' java-version: 21 @@ -29,7 +29,7 @@ jobs: server-password: MAVEN_CENTRAL_PASSWORD - name: Cache Maven packages - uses: actions/cache@v3.0.11 + uses: actions/cache@v4.1.2 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -44,7 +44,7 @@ jobs: run: xvfb-run mvn package -P release -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} - name: Set up Apache Maven Central - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v4.5.0 with: distribution: 'zulu' java-version: 21 diff --git a/README.md b/README.md index ca4d26b7d..12814fe36 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Yaeger requires JDK21, and is available through the Maven Central Repository. com.github.han-yaeger yaeger - 2023.2024 + 2024.2025 ``` diff --git a/architecture/class-overview.md b/architecture/class-overview.md new file mode 100644 index 000000000..9c64798d6 --- /dev/null +++ b/architecture/class-overview.md @@ -0,0 +1,15 @@ +# A guide through Yaeger's internals + +After reading this guide, you should have a basic picture of how Yaeger's internals work. Not everything will be covered, +but the basic setup should be clear and it should be possible to figure out how the missing parts work. + +## Introduction + +To get insight into how Yaeger is built, we will be using different views on its internals. We will base this on the game +of Pac-Man. + +![Pac-Man](images/pacman.png) + +## Base classes for Scenes and Entities + + diff --git a/architecture/images/pacman.png b/architecture/images/pacman.png new file mode 100644 index 000000000..97ebca3a4 Binary files /dev/null and b/architecture/images/pacman.png differ diff --git a/architecture/plantuml/classdiagrams/user-perspective-base.puml b/architecture/plantuml/classdiagrams/user-perspective-base.puml new file mode 100644 index 000000000..0f8188217 --- /dev/null +++ b/architecture/plantuml/classdiagrams/user-perspective-base.puml @@ -0,0 +1,56 @@ +@startuml +'https://plantuml.com/class-diagram + +class YaegerGame { + setupGame(): void + setupScenes(): void + addScene(int, YaegerScene): void +} + +interface YaegerScene { + setupScene(): void + setupEntities(): void +} + +abstract class StaticScene implements YaegerScene{ + addEntity(YaegerEntity): void +} + +abstract class DynamicScene extends StaticScene{ +} + +abstract class YaegerEntity { +} + +abstract class CircleEntity extends YaegerEntity { +} + +abstract class DynamicCircleEntity extends CircleEntity { +} + +abstract class EllipseEntity extends YaegerEntity { +} + +abstract class DynamicEllipseEntity extends EllipseEntity { +} + +abstract class RectangleEntity extends YaegerEntity { +} + +abstract class DynamicRectangleEntity extends RectangleEntity { +} + +abstract class SpriteEntity extends YaegerEntity { +} + +abstract class DynamicSpriteEntity extends SpriteEntity { +} + +abstract class TextEntity extends YaegerEntity { +} + +abstract class DynamicTextEntity extends TextEntity { +} + + +@enduml \ No newline at end of file diff --git a/architecture/plantuml/classdiagrams/user-perspective-tilemap.puml b/architecture/plantuml/classdiagrams/user-perspective-tilemap.puml new file mode 100644 index 000000000..1390e26b5 --- /dev/null +++ b/architecture/plantuml/classdiagrams/user-perspective-tilemap.puml @@ -0,0 +1,36 @@ +@startuml +'https://plantuml.com/class-diagram + +class YaegerGame { + setupGame(): void + setupScenes(): void + addScene(int, YaegerScene): void +} + +interface YaegerScene { + setupScene(): void + setupEntities(): void +} + +abstract class StaticScene implements YaegerScene{ + addEntity(YaegerEntity): void +} + +abstract class DynamicScene extends StaticScene{ +} + +abstract class YaegerEntity { +} + +interface TileMapContainer { + setupTileMaps(): void + addTileMap(TileMap): void +} + +abstract class TileMap{ + setupEntities(): void + addEntity(int, Class): void +} + + +@enduml \ No newline at end of file diff --git a/docs/creating-entities.md b/docs/creating-entities.md index 1d1b90281..08407e951 100644 --- a/docs/creating-entities.md +++ b/docs/creating-entities.md @@ -1,6 +1,6 @@ # Creating entities -All available entities, expect the `TextEntity`, are abstract classes, meaning +All available entities, except the `TextEntity`, are abstract classes, meaning they should be extended to create an instance. After creating a class, an instance should be created, which can then be added to a `YaegerScene`, or a `CompositeEntity` through the `addEntity(YaegerEntity)` method. diff --git a/docs/faq.md b/docs/faq.md index 916afe9a3..ccba40a86 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -52,7 +52,8 @@ group them within their specific methods. If you have a machine with Apple Silicon you might come across an error in the build process like this: -![Error building because of libraries that cannot be linked](./images/00-mac-error.png) +![Error building because of libraries that cannot be linked](images/00-mac-error.png) + To solve this you have to change the architecture of your JDK to one that is not specific to an ARM CPU. diff --git a/docs/timing-things.md b/docs/timing-things.md index fdc952994..389fd93b1 100644 --- a/docs/timing-things.md +++ b/docs/timing-things.md @@ -6,15 +6,22 @@ implementations of `YaegerScene` available: a `StaticScene` and a contains a Game World Update (GWU) to which all instances of `DynamicEntity` added to the scene will listen. -This chapter will discuss the different ways in the GWU can be used within +This chapter will discuss the different ways in which the GWU can be used within Yaeger. It will start by discussing how the GWU gets delegated to all -objects, after which different ways to use in within your scene of entity. +objects, after which different ways are discussed to use it within your scene or +entity. ## How the GWU is delegated to all objects The GWU is initiated by the `DynamicScene`, and handed down to all dynamic -entities that were added to the scene. This is done in the same order as in -which they were added to the scene. +entities, timers, spawners and composite entities that were added to the scene. +This is done in the same order as in which they were added to the scene. + +From a programming point-of-view, the GWU is a timed method call. The +`DynamicScene` calls its `update()` method, which then calls all the `update()` +methods of all the dynamic entities, timers, spawners and composite entities. If +those objects themself also contain child-objects, their `update()` method is +then also called. And so forth. ![Update Delegation](images/update-delegation.png) diff --git a/pom.xml b/pom.xml index d1ef123a3..0c8f83560 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.han-yaeger yaeger - 2023.2024 + 2024.2025 jar @@ -15,7 +15,7 @@ UTF-8 21 - 21.0.1 + 23.0.1 han-yaeger_yaeger han-yaeger https://sonarcloud.io @@ -155,7 +155,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.12 prepare-agent @@ -165,13 +165,6 @@ - - - org.ow2.asm - asm - 9.5 - - com/github/hanyaeger/core/guice/**/* @@ -217,6 +210,7 @@ + org.openjfx @@ -258,20 +252,27 @@ org.mockito mockito-core - 5.5.0 + 5.13.0 test org.testfx testfx-core - 4.0.16-alpha + 4.0.18 test org.testfx openjfx-monocle - jdk-12.0.1+2 + 21.0.2 test + + + com.google.guava + guava + 33.3.1-jre + diff --git a/release.md b/release.md index 2263e60ee..73df5e93f 100644 --- a/release.md +++ b/release.md @@ -1,18 +1,17 @@ # Changes in this release -## Configuration - -* Updated Mockito to 4.8.0 -* Updated jUnit to 5.9.1 -* Updated JavaFX to 19 +This release is mainly focussed on updated the dependencies and fixing bugs. -## Refactor - -## Features +## Configuration -* Added a new animation system, in which parts of a sprite-sheet can be - encapsulated by a Java-object. This will make it far easier to fully animate - an entity (#239). +* Updated Jacoco to 0.8.12 +* Updated JavaFX to 23.0.1 +* Updated testfx-code to 5.13.0 +* Updated openjfx-monocle to 21.0.2 +* Updated Guava to 33.3.1-jr so ensure Google Guice does not use the broken version +* Updated Mockito to 5.13.0 ## Bugfixes +* Fixed two issues related to the bounding boxes in Composite Entities (#249, #268) +* Fixed #265 (getSpeedInDirection with same direction returns 0 instead of actual speed). Thanks to @Liam-Rougoor. diff --git a/src/main/java/com/github/hanyaeger/core/entities/Bounded.java b/src/main/java/com/github/hanyaeger/core/entities/Bounded.java index 65bd3be11..55c819238 100644 --- a/src/main/java/com/github/hanyaeger/core/entities/Bounded.java +++ b/src/main/java/com/github/hanyaeger/core/entities/Bounded.java @@ -1,13 +1,11 @@ package com.github.hanyaeger.core.entities; -import com.github.hanyaeger.api.Coordinate2D; import com.github.hanyaeger.api.entities.CompositeEntity; import com.github.hanyaeger.api.scenes.YaegerScene; import com.github.hanyaeger.core.scenes.DimensionsProvider; import javafx.geometry.BoundingBox; import javafx.geometry.Bounds; import javafx.scene.Node; -import javafx.scene.layout.Pane; /** * Implementing this interface exposes the {@link Bounded#getBoundingBox()} and method, which returns the bounds, aka @@ -25,14 +23,7 @@ public interface Bounded extends DimensionsProvider, GameNode { * @return the {@link Bounds} */ default Bounds getBoundingBox() { - - return getNode().map(node -> { - var newLocation = calculateLocation(node); - return new BoundingBox(newLocation.getX(), - newLocation.getY(), - node.getBoundsInParent().getWidth(), - node.getBoundsInParent().getHeight()); - }).orElse(new BoundingBox(0, 0, 0, 0)); + return getNode().map(node -> node.localToScene(node.getLayoutBounds())).orElse(new BoundingBox(0, 0, 0, 0)); } private Bounds getBounds() { @@ -48,30 +39,4 @@ default double getWidth() { default double getHeight() { return getBounds().getHeight(); } - - /** - * Since a {@link Node} can be either part of the {@link Pane}, or of a {@link javafx.scene.Group}, which itself - * can also be part of the {@link Pane} or another {@link javafx.scene.Group}, which itself can be... , this - * method recursively calculates ({@link #translateCoordinates(Node, Coordinate2D)} does the actual recursive work) - * the coordinate of the {@link} projected on the {@link Pane}. This way it is - * possible to use the {@link Node#intersects(Bounds)} method to perform collision detection. - * - * @param node that {@link Node} for which the coordinates need to be calculated - * @return the {@link Coordinate2D} of the node, as projected on the {@link Pane} - */ - private Coordinate2D calculateLocation(final Node node) { - if (node == null) { - return new Coordinate2D(10, 10); - } - - return translateCoordinates(node, new Coordinate2D()); - } - - private Coordinate2D translateCoordinates(final Node node, final Coordinate2D translatedCoordinate) { - if (node == null || node instanceof Pane) { - return translatedCoordinate; - } else { - return translateCoordinates(node.getParent(), translatedCoordinate.add(new Coordinate2D(node.getBoundsInParent().getMinX(), node.getBoundsInParent().getMinY()))); - } - } } diff --git a/src/main/java/com/github/hanyaeger/core/entities/motion/MotionApplier.java b/src/main/java/com/github/hanyaeger/core/entities/motion/MotionApplier.java index 14d5b9ade..1457280b8 100644 --- a/src/main/java/com/github/hanyaeger/core/entities/motion/MotionApplier.java +++ b/src/main/java/com/github/hanyaeger/core/entities/motion/MotionApplier.java @@ -67,14 +67,14 @@ public double getSpeedInDirection(final Direction direction) { @Override public double getSpeedInDirection(final double direction) { var calculatedSpeed = 0D; - if (Double.compare(getDirection(), direction) != 0) { - final var normalizedVector = createVector(1, direction); - final var dotProduct = normalizedVector.dotProduct(motion); - if (dotProduct > 0) { - calculatedSpeed = calculateDenormalizedVector(normalizedVector, motion).magnitude(); - } + final var normalizedVector = createVector(1, direction); + final var dotProduct = normalizedVector.dotProduct(motion); + + if (dotProduct > 0) { + calculatedSpeed = calculateDenormalizedVector(normalizedVector, motion).magnitude(); } + return calculatedSpeed; } diff --git a/src/main/java/com/github/hanyaeger/core/scenes/splash/SplashScene.java b/src/main/java/com/github/hanyaeger/core/scenes/splash/SplashScene.java index 8980947ee..100fcbf4e 100644 --- a/src/main/java/com/github/hanyaeger/core/scenes/splash/SplashScene.java +++ b/src/main/java/com/github/hanyaeger/core/scenes/splash/SplashScene.java @@ -31,7 +31,7 @@ public class SplashScene extends DynamicScene implements TimerContainer { public void setupScene() { setBrightness(-1); setBackgroundImage("yaegerimages/splash-bg.jpg"); - var splashSound = new SoundClip("yaegersounds/yaeger.mp3"); + var splashSound = new SoundClip("yaegersounds/yaeger.wav"); splashSound.play(); } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index ab945e066..4a624ec88 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -37,4 +37,5 @@ exports com.github.hanyaeger.core.media to com.google.guice; opens yaegerimages; + opens yaegersounds; } diff --git a/src/main/resources/yaegersounds/yaeger.mp3 b/src/main/resources/yaegersounds/yaeger.mp3 deleted file mode 100644 index 216cb6fde..000000000 Binary files a/src/main/resources/yaegersounds/yaeger.mp3 and /dev/null differ diff --git a/src/main/resources/yaegersounds/yaeger.wav b/src/main/resources/yaegersounds/yaeger.wav new file mode 100644 index 000000000..4189e4a70 Binary files /dev/null and b/src/main/resources/yaegersounds/yaeger.wav differ diff --git a/src/test/java/com/github/hanyaeger/api/entities/SceneBorderCrossingWatcherTest.java b/src/test/java/com/github/hanyaeger/api/entities/SceneBorderCrossingWatcherTest.java index b93c46852..f6d228368 100644 --- a/src/test/java/com/github/hanyaeger/api/entities/SceneBorderCrossingWatcherTest.java +++ b/src/test/java/com/github/hanyaeger/api/entities/SceneBorderCrossingWatcherTest.java @@ -7,7 +7,6 @@ import javafx.geometry.BoundingBox; import javafx.geometry.Bounds; import javafx.scene.Node; -import javafx.scene.Scene; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,13 +17,14 @@ class SceneBorderCrossingWatcherTest { - private final static double SCENE_HEIGHT = 100; - private final static double SCENE_WIDTH = 100; - private final static BoundingBox BOUNDS_IN_PARENT = new BoundingBox(10, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_LEFT = new BoundingBox(-20, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_RIGHT = new BoundingBox(110, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_BOTTOM = new BoundingBox(10, 100, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_TOP = new BoundingBox(10, -20, 10, 10); + private static final double SCENE_HEIGHT = 100; + private static final double SCENE_WIDTH = 100; + + private static final BoundingBox BOUNDS_IN_PARENT = new BoundingBox(10, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_LEFT = new BoundingBox(-20, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_RIGHT = new BoundingBox(110, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_BOTTOM = new BoundingBox(10, 100, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_TOP = new BoundingBox(10, -20, 10, 10); private SceneBorderCrossingWatcherImpl sut; private Node node; private MotionApplier motionApplier; @@ -55,7 +55,8 @@ void testWatchForBoundaryCrossingReturnsAnUpdatable() { @Test void testBoundaryNotCrossed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_IN_PARENT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_IN_PARENT); + when(node.localToScene(BOUNDS_IN_PARENT)).thenReturn(BOUNDS_IN_PARENT); var updatable = sut.watchForBoundaryCrossing(); @@ -69,7 +70,8 @@ void testBoundaryNotCrossed() { @Test void testBoundaryLeftCrossedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.localToScene(BOUNDS_CROSSED_LEFT)).thenReturn(BOUNDS_CROSSED_LEFT); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryCrossing(); @@ -84,7 +86,8 @@ void testBoundaryLeftCrossedWithZeroSpeed() { @Test void testBoundaryLeftCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.localToScene(BOUNDS_CROSSED_LEFT)).thenReturn(BOUNDS_CROSSED_LEFT); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryCrossing(); @@ -99,7 +102,8 @@ void testBoundaryLeftCrossedWithNonZeroSpeed() { @Test void testBoundaryRightCrossedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.localToScene(BOUNDS_CROSSED_RIGHT)).thenReturn(BOUNDS_CROSSED_RIGHT); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryCrossing(); @@ -114,7 +118,8 @@ void testBoundaryRightCrossedWithZeroSpeed() { @Test void testBoundaryRightCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.localToScene(BOUNDS_CROSSED_RIGHT)).thenReturn(BOUNDS_CROSSED_RIGHT); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryCrossing(); @@ -129,7 +134,8 @@ void testBoundaryRightCrossedWithNonZeroSpeed() { @Test void testBoundaryBottomCrossedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.localToScene(BOUNDS_CROSSED_BOTTOM)).thenReturn(BOUNDS_CROSSED_BOTTOM); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryCrossing(); @@ -144,7 +150,8 @@ void testBoundaryBottomCrossedWithZeroSpeed() { @Test void testBoundaryBottomCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.localToScene(BOUNDS_CROSSED_BOTTOM)).thenReturn(BOUNDS_CROSSED_BOTTOM); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryCrossing(); @@ -159,7 +166,8 @@ void testBoundaryBottomCrossedWithNonZeroSpeed() { @Test void testBoundaryTopCrossedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.localToScene(BOUNDS_CROSSED_TOP)).thenReturn(BOUNDS_CROSSED_TOP); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryCrossing(); @@ -174,7 +182,8 @@ void testBoundaryTopCrossedWithZeroSpeed() { @Test void testBoundaryTopCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.localToScene(BOUNDS_CROSSED_TOP)).thenReturn(BOUNDS_CROSSED_TOP); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryCrossing(); diff --git a/src/test/java/com/github/hanyaeger/api/entities/SceneBorderTouchingWatcherTest.java b/src/test/java/com/github/hanyaeger/api/entities/SceneBorderTouchingWatcherTest.java index 68730f834..e1ce2e78d 100644 --- a/src/test/java/com/github/hanyaeger/api/entities/SceneBorderTouchingWatcherTest.java +++ b/src/test/java/com/github/hanyaeger/api/entities/SceneBorderTouchingWatcherTest.java @@ -5,9 +5,7 @@ import com.github.hanyaeger.core.entities.motion.MotionApplier; import com.github.hanyaeger.api.scenes.SceneBorder; import javafx.geometry.BoundingBox; -import javafx.geometry.Bounds; import javafx.scene.Node; -import javafx.scene.Scene; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -19,13 +17,13 @@ class SceneBorderTouchingWatcherTest { - private final static double SCENE_HEIGHT = 100; - private final static double SCENE_WIDTH = 100; - private final static BoundingBox BOUNDS_IN_PARENT = new BoundingBox(10, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_LEFT = new BoundingBox(-20, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_RIGHT = new BoundingBox(110, 10, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_BOTTOM = new BoundingBox(10, 100, 10, 10); - private final static BoundingBox BOUNDS_CROSSED_TOP = new BoundingBox(10, -20, 10, 10); + private static final double SCENE_HEIGHT = 100; + private static final double SCENE_WIDTH = 100; + private static final BoundingBox BOUNDS_IN_PARENT = new BoundingBox(10, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_LEFT = new BoundingBox(-20, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_RIGHT = new BoundingBox(110, 10, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_BOTTOM = new BoundingBox(10, 100, 10, 10); + private static final BoundingBox BOUNDS_CROSSED_TOP = new BoundingBox(10, -20, 10, 10); private SceneBorderTouchingWatcherImpl sut; private Node node; private MotionApplier motionApplier; @@ -56,7 +54,8 @@ void testWatchForBoundaryTouchingReturnsAnUpdatable() { @Test void testBoundaryNotTouched() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_IN_PARENT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_IN_PARENT); + when(node.localToScene(BOUNDS_IN_PARENT)).thenReturn(BOUNDS_IN_PARENT); var updatable = sut.watchForBoundaryTouching(); // Act @@ -84,7 +83,8 @@ void testBoundaryLeftCrossedWithZeroSpeed() { @Test void testBoundaryLeftCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_LEFT); + when(node.localToScene(BOUNDS_CROSSED_LEFT)).thenReturn(BOUNDS_CROSSED_LEFT); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryTouching(); @@ -99,7 +99,8 @@ void testBoundaryLeftCrossedWithNonZeroSpeed() { @Test void testBoundaryRightCrossedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.localToScene(BOUNDS_CROSSED_RIGHT)).thenReturn(BOUNDS_CROSSED_RIGHT); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryTouching(); @@ -114,7 +115,8 @@ void testBoundaryRightCrossedWithZeroSpeed() { @Test void testBoundaryRightCrossedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_RIGHT); + when(node.localToScene(BOUNDS_CROSSED_RIGHT)).thenReturn(BOUNDS_CROSSED_RIGHT); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryTouching(); @@ -129,7 +131,8 @@ void testBoundaryRightCrossedWithNonZeroSpeed() { @Test void testBoundaryBottomTouchedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.localToScene(BOUNDS_CROSSED_BOTTOM)).thenReturn(BOUNDS_CROSSED_BOTTOM); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryTouching(); @@ -144,7 +147,8 @@ void testBoundaryBottomTouchedWithZeroSpeed() { @Test void testBoundaryBottomTouchedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_BOTTOM); + when(node.localToScene(BOUNDS_CROSSED_BOTTOM)).thenReturn(BOUNDS_CROSSED_BOTTOM); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryTouching(); @@ -159,7 +163,8 @@ void testBoundaryBottomTouchedWithNonZeroSpeed() { @Test void testBoundaryTopTouchedWithZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.localToScene(BOUNDS_CROSSED_TOP)).thenReturn(BOUNDS_CROSSED_TOP); when(motionApplier.getSpeed()).thenReturn(0d); var updatable = sut.watchForBoundaryTouching(); @@ -174,7 +179,8 @@ void testBoundaryTopTouchedWithZeroSpeed() { @Test void testBoundaryTopTouchedWithNonZeroSpeed() { // Arrange - when(node.getBoundsInParent()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.getLayoutBounds()).thenReturn(BOUNDS_CROSSED_TOP); + when(node.localToScene(BOUNDS_CROSSED_TOP)).thenReturn(BOUNDS_CROSSED_TOP); when(motionApplier.getSpeed()).thenReturn(1d); var updatable = sut.watchForBoundaryTouching(); diff --git a/src/test/java/com/github/hanyaeger/core/entities/BoundedTest.java b/src/test/java/com/github/hanyaeger/core/entities/BoundedTest.java index 25d1b0824..7a82f689a 100644 --- a/src/test/java/com/github/hanyaeger/core/entities/BoundedTest.java +++ b/src/test/java/com/github/hanyaeger/core/entities/BoundedTest.java @@ -66,7 +66,7 @@ void getBoundingBoxDelegatesToGameNodeIfPresent() { sut.getBoundingBox(); // Assert - Mockito.verify(node, times(4)).getBoundsInParent(); + Mockito.verify(node).getLayoutBounds(); } @Test @@ -96,7 +96,7 @@ void getHeightReturnValueFromBounds() { } @Test - void getBoundingBoxReturnsMinimalBoxOnDefaultLocationIfNodeIsNull(){ + void getBoundingBoxReturnsMinimalBoxOnDefaultLocationIfNodeIsNull() { // Arrange var emptySut = new EmptyGameNodeBoundedImpl(); diff --git a/src/test/java/com/github/hanyaeger/core/entities/motion/MotionApplierTest.java b/src/test/java/com/github/hanyaeger/core/entities/motion/MotionApplierTest.java index e16469acd..4090b3e08 100644 --- a/src/test/java/com/github/hanyaeger/core/entities/motion/MotionApplierTest.java +++ b/src/test/java/com/github/hanyaeger/core/entities/motion/MotionApplierTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import static org.junit.jupiter.api.Assertions.*; @@ -209,14 +211,14 @@ void alterSpeedWithNegativeValueDecrementsSpeedTest() { @Test void getSpeedReturnsCorrectValueTest() { // Arrange - var SPEED = 3.7; - sut.setMotion(SPEED, Direction.UP.getValue()); + var expected = 3.7; + sut.setMotion(expected, Direction.UP.getValue()); // Act var speed = sut.getSpeed(); // Assert - assertEquals(SPEED, speed, DELTA); + assertEquals(expected, speed, DELTA); } @Test @@ -235,14 +237,14 @@ void setDirectionRIGHTForSpeedOneCreatesRightVectorTest() { @Test void setDirectionToUPForSpeedOneCreatesUpVectorTest() { // Arrange - sut.setSpeed(1); + sut.setSpeed(2); // Act sut.setDirection(Direction.UP); // Assert assertEquals(0, sut.get().getX(), DELTA); - assertEquals(-1, sut.get().getY(), DELTA); + assertEquals(-2, sut.get().getY(), DELTA); } @Test @@ -327,14 +329,14 @@ void resetSpeedAfterSpeedHasBeenSetToZeroCreatesCorrectVectorTest() { @Test void getDirectionForDirectionBelow180TestReturnsCorrectValue() { // Arrange - final double DIRECTION = 42; - sut.setMotion(1, DIRECTION); + final double expected = 42; + sut.setMotion(1, expected); // Act - var direction = sut.getDirection(); + var actual = sut.getDirection(); // Assert - assertEquals(DIRECTION, direction, DELTA); + assertEquals(expected, actual, DELTA); } @Test @@ -364,14 +366,14 @@ void getDirectionsReturnsNumericValueWhenEnumIsForDirectionWasUsedInMotionTest() @Test void getDirectionForDirectionAbove180ReturnsCorrectValueTest() { // Arrange - final double DIRECTION = 189; - sut.setMotion(1, DIRECTION); + final double expected = 189; + sut.setMotion(1, expected); // Act - var direction = sut.getDirection(); + var actual = sut.getDirection(); // Assert - assertEquals(DIRECTION, direction, DELTA); + assertEquals(expected, actual, DELTA); } @Test @@ -390,7 +392,7 @@ void getDirectionAfterSpeedSetTo0ReturnsCorrectDirection(){ @Test void changeDirectionWithZeroDoesNotChangeAngleTest() { // Arrange - sut.setMotion(1, Direction.DOWN.getValue()); + sut.setMotion(2, Direction.DOWN.getValue()); // Act sut.changeDirection(0); @@ -743,6 +745,20 @@ void nullifySpeedInZeroDirectionDoesNotResultInNaNTest() { @Nested class GetSpeedInDirectionTests { + @ParameterizedTest + @EnumSource(Direction.class) + void getSpeedInExactDirectionGivesSpeedTest(Direction direction){ + // Arrange + var speed = 3.7; + + // Act + sut.setMotion(speed, direction); + var speedInDirection = sut.getSpeedInDirection(direction); + + // Assert + assertEquals(3.7, speedInDirection, DELTA); + } + @Test void getSpeedInOppositeDirectionGives0Test() { // Arrange diff --git a/src/test/java/com/github/hanyaeger/core/scenes/delegates/BackgroundDelegateTest.java b/src/test/java/com/github/hanyaeger/core/scenes/delegates/BackgroundDelegateTest.java index b2615dfa0..86561baeb 100644 --- a/src/test/java/com/github/hanyaeger/core/scenes/delegates/BackgroundDelegateTest.java +++ b/src/test/java/com/github/hanyaeger/core/scenes/delegates/BackgroundDelegateTest.java @@ -7,18 +7,18 @@ import javafx.scene.layout.Background; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; class BackgroundDelegateTest { private static final String URL_AUDIO = "audio/testaudio.mp3"; - private static final String URL_AUDIO_2 = "audio/testaudio2.mp3"; private static final String URL_IMAGE = "testImage.png"; private BackgroundDelegate sut; private BackgroundFactory backgroundFactory; @@ -62,7 +62,7 @@ void getVolumeReturns0() { var actual = sut.getVolume(); // Assert - Assertions.assertEquals(expected, actual); + assertEquals(expected, actual); } } @@ -133,7 +133,7 @@ void getVolumeDelegatesToBackgroundAudioPlayer() { var actual = sut.getVolume(); // Assert - Assertions.assertEquals(expected, actual); + assertEquals(expected, actual); } } @@ -166,7 +166,7 @@ void setBackgroundColorWithNullPaneDoesNotBreak() { var color = Color.YELLOW; // Act & Assert - Assertions.assertAll(() -> paneIsNullSut.setBackgroundColor(color)); + assertAll(() -> paneIsNullSut.setBackgroundColor(color)); } @Test