Skip to content

Commit

Permalink
[bugfix] Finally correctly fixed #268 by using the JavaFX native coor…
Browse files Browse the repository at this point in the history
…dinate transformations (#268)
  • Loading branch information
meronbrouwer committed Nov 26, 2024
1 parent e054cf6 commit cbe486d
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 53 deletions.
36 changes: 2 additions & 34 deletions src/main/java/com/github/hanyaeger/core/entities/Bounded.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.github.hanyaeger.core.scenes.DimensionsProvider;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.layout.Pane;

Expand All @@ -25,14 +26,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() {
Expand All @@ -48,30 +42,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())));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import javafx.scene.Scene;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Optional;

Expand All @@ -20,6 +21,8 @@ class SceneBorderCrossingWatcherTest {

private final static double SCENE_HEIGHT = 100;
private final static double SCENE_WIDTH = 100;
private final static Bounds BOUNDS_IN_PARENT_BOUNDS = new BoundingBox(10, 10, 10, 10);

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);
Expand Down Expand Up @@ -55,7 +58,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();

Expand All @@ -69,7 +73,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();
Expand All @@ -84,7 +89,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();
Expand All @@ -99,7 +105,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();
Expand All @@ -114,7 +121,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();
Expand All @@ -129,7 +137,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();
Expand All @@ -144,7 +153,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();
Expand All @@ -159,7 +169,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();
Expand All @@ -174,7 +185,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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
Expand Down Expand Up @@ -84,7 +85,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();
Expand All @@ -99,7 +101,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();
Expand All @@ -114,7 +117,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();
Expand All @@ -129,7 +133,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();
Expand All @@ -144,7 +149,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();
Expand All @@ -159,7 +165,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();
Expand All @@ -174,7 +181,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void getBoundingBoxDelegatesToGameNodeIfPresent() {
sut.getBoundingBox();

// Assert
Mockito.verify(node, times(4)).getBoundsInParent();
Mockito.verify(node).getLayoutBounds();
}

@Test
Expand Down Expand Up @@ -96,7 +96,7 @@ void getHeightReturnValueFromBounds() {
}

@Test
void getBoundingBoxReturnsMinimalBoxOnDefaultLocationIfNodeIsNull(){
void getBoundingBoxReturnsMinimalBoxOnDefaultLocationIfNodeIsNull() {
// Arrange
var emptySut = new EmptyGameNodeBoundedImpl();

Expand Down

0 comments on commit cbe486d

Please sign in to comment.