在重力作用下弹跳的球不会停在界外
The bouncing ball under gravity does not stop at bounds
我正在申请,需要一个在重力作用下弹跳的球。球弹得很好,但它永远不会停止。
我尝试打印停止点的坐标以及速度。这是其中一个案例的输出:
Found it... line 24. (0.00)i + (-0.01)j {14.14(0.79)} (-1.79, 651.57)
因此球停在高度 651.67 而边界是 600。这是另一种情况:
Found it... line 24. (0.00)i + (-0.01)j {14.14(0.79)} (-1.79, 1624.58)
代码如下:
GUI.java
import java.util.Timer;
import java.util.TimerTask;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.stage.Stage;
public class GUI extends Application {
@Override
public void start(Stage theStage) throws Exception {
theStage.setTitle("Bouncy Ball");
Group root = new Group();
Scene theScene = new Scene(root);
theStage.setScene(theScene);
Canvas canvas = new Canvas(750, 600);
root.getChildren().add(canvas);
CircleSprite sprite = new CircleSprite(30, new Point(50, 50));
root.getChildren().add(sprite.image);
sprite.setVelocity(new Vector(new Point(10, 10)));
theStage.show();
theStage.setOnCloseRequest(e -> {
System.exit(0);
});
AnimationTimer gameLoop = new AnimationTimer() {
@Override
public void handle(long now) {
if (sprite.update(new Bounds(700, 600))) {
this.stop();
}
}
};
gameLoop.start();
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Vector velocity = sprite.getVelocity();
velocity.setYComponent(velocity.getYComponent() + 1);
if (Math.abs(sprite.getVelocity().getYComponent()) <= 0.01
&& sprite.getCentre().getY() + 2 * sprite.getRadius() >= 500) {
System.out.println("Found it... line 55");
cancel();
}
}
}, 0, 100);
}
public static void main(String[] args) {
launch(args);
}
}
CircleSprite.java
public class CircleSprite extends Circle {
public javafx.scene.shape.Circle image;
public CircleSprite(long radius, Point centre) {
super(radius, centre);
image = new javafx.scene.shape.Circle(centre.getX(), centre.getY(), radius);
}
public boolean update(Bounds bounds) {
Point pos = this.getCentre();
Vector velocity = this.getVelocity();
Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent());
image.setLayoutX(finalPos.getX());
image.setLayoutY(finalPos.getY());
setCentre(finalPos);
if (finalPos.getX() <= 0 || finalPos.getX() + 2 * getRadius() >= bounds.maxX) {
velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75);
}
if (finalPos.getY() <= 0 || finalPos.getY() + 2 * getRadius() >= bounds.maxY) {
velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75);
}
if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) {
System.out.println("Found it... line 24" + velocity + " " + getCentre());
return true;
}
return false;
}
}
Bounds.java
public class Bounds {
public double maxX;
public double maxY;
public Bounds(double maxX, double maxY) {
this.maxX = maxX;
this.maxY = maxY;
}
}
Circle.java
public class Circle extends Shape {
private long radius;
private Point centre;
public Circle(long radius, Point centre) {
this.radius = radius;
this.centre = centre;
this.setVelocity(new Vector(new Point(0.0d, 0.0d), new Point(0, 0)));
this.setMass(0);
this.setRestitution(1);
this.setAcceleration(new Vector(new Point(0, 0), new Point(0, 0)));
}
/*
* Testing for whether or not two circles intersect is very simple: take the
* radii of the two circles and add them together, then check to see if this sum
* is greater than the distance between the two circles.
*/
public boolean isColliding(Circle a, Circle b) {
long dist = a.getRadius() + b.getRadius();
// In general multiplication is a much cheaper operation than taking the square
// root of a value.
return ((dist * dist) < (a.getCentre().getX() - b.getCentre().getX())
* (a.getCentre().getX() - b.getCentre().getX())
+ (a.getCentre().getY() - b.getCentre().getY()) * (a.getCentre().getY() - b.getCentre().getY()));
}
public long getRadius() {
return this.radius;
}
public void setRadius(long radius) {
this.radius = radius;
}
public Point getCentre() {
return this.centre;
}
public void setCentre(Point centre) {
this.centre = centre;
}
}
Shape.java
public class Shape {
private Vector velocity;
private Vector acceleration;
private long mass;
private double invMass;
private float restitution;
public Vector getAcceleration() {
return this.acceleration;
}
public void setAcceleration(Vector acceleration) {
this.acceleration = acceleration;
}
public long getMass() {
return this.mass;
}
public void setMass(long mass) {
this.mass = mass;
this.setInvMass(mass);
}
public Vector getVelocity() {
return this.velocity;
}
public void setVelocity(Vector velocity) {
this.velocity = velocity;
}
public double getInvMass() {
return this.invMass;
}
private void setInvMass(long mass) {
if (mass == 0) {
invMass = Long.MAX_VALUE;
return;
}
this.invMass = 1.0d / (double) mass;
}
public float getRestitution() {
return this.restitution;
}
public void setRestitution(float restitution) {
this.restitution = restitution;
}
}
Vector.java
public class Vector {
private Point p1;
private Point p2;
private double xComponent;
private double yComponent;
private double angle;
private double magnitude;
/*
* The constructor makes a vector crossing through two points p1 and p2.
*
* @param p1 The source point(x1, x2)
*/
public Vector(Point p1, Point p2) {
this.p1 = p1;
this.p2 = p2;
this.xComponent = this.p2.getX() - this.p1.getX();
this.yComponent = this.p2.getY() - this.p1.getY();
this.angle = Math.atan2(this.yComponent, this.xComponent);
this.magnitude = Math.sqrt(this.xComponent * this.xComponent + this.yComponent * this.yComponent);
}
public Vector(Point p2) {
Point p1 = new Point(0, 0);
this.p1 = p1;
this.p2 = p2;
this.xComponent = this.p2.getX() - this.p1.getX();
this.yComponent = this.p2.getY() - this.p1.getY();
this.angle = Math.atan2(this.yComponent, this.xComponent);
this.magnitude = Math.sqrt(this.xComponent * this.xComponent + this.yComponent * this.yComponent);
}
public Vector(double magnitude, Vector unitVector) {
scaledProduct(magnitude, unitVector);
}
private void scaledProduct(double magnitude, Vector unitVector) {
Point point = new Point(magnitude * unitVector.getXComponent(), magnitude * unitVector.getYComponent());
new Vector(point);
}
public static Vector scalarProduct(double magnitude, Vector unitVector) {
Point point = new Point(magnitude * unitVector.getXComponent(), magnitude * unitVector.getYComponent());
return new Vector(point);
}
public static double dotProduct(Vector v1, Vector v2) {
return (v1.xComponent * v2.xComponent + v1.yComponent * v2.yComponent);
}
public static Vector sum(Vector v1, Vector v2) {
return new Vector(new Point(v1.getXComponent() + v2.getXComponent(), v1.getYComponent() + v2.getYComponent()));
}
public static Vector difference(Vector from, Vector vector) {
return new Vector(new Point(from.getXComponent() - vector.getXComponent(),
from.getYComponent() - vector.getYComponent()));
}
public static double angleBetween(Vector v1, Vector v2) {
return Math.acos(Vector.dotProduct(v1, v2) / (v1.getMagnitude() * v2.getMagnitude()));
}
public Point getP1() {
return this.p1;
}
public void setP1(Point p1) {
this.p1 = p1;
}
public Point getP2() {
return this.p2;
}
public void setP2(Point p2) {
this.p2 = p2;
}
public double getXComponent() {
return this.xComponent;
}
public void setXComponent(double d) {
this.xComponent = d;
}
public double getYComponent() {
return this.yComponent;
}
public void setYComponent(double d) {
this.yComponent = d;
}
public double getAngle() {
return this.angle;
}
public void setAngle(double angle) {
this.angle = angle;
}
public double getMagnitude() {
return this.magnitude;
}
public void setMagnitude(double length) {
this.magnitude = length;
}
@Override
public boolean equals(Object v) {
Vector vector = (Vector) v;
return ((this.xComponent == vector.xComponent) && (this.yComponent == vector.yComponent));
}
@Override
public String toString() {
return String.format("(%.2f)i + (%.2f)j {%.2f(%.2f)}", this.xComponent, this.yComponent, this.magnitude,
this.angle);
}
}
Point.java
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public static double distance(Point p1, Point p2) {
return Math.sqrt(
(p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) + (p1.getY() - p2.getY()) * (p1.getY() - p2.getY()));
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
@Override
public String toString() {
return String.format("(%.2f, %.2f)", this.x, this.y);
}
}
代码有什么问题?我知道 GUI.java 和 CircleSprite.java 中的退出条件有问题,但不知道是什么。有两件事困扰着我:
1. Why is the height out of bound when it stops?
2. Why does the x goes negative?
这里发生的情况如下(仅考虑 x 维度;同样适用于 y):
球以v
的速度过界。您反转速度并降低其幅度。这可能会导致新速度不够高,无法在下一个更新步骤中回到边界,并且您再次反转速度以进一步降低速度。这导致球在边界外以越来越小的步幅来回移动,有效地给人以停止的印象。
值示例:
Frame 1
vx = -16
x = 1
Frame 2
vx = 12
x = -15
Frame 3
vx = -9
x = -3
Frame 4
vx = -6.75
x = -12
...
有两种方法可以解决这个问题:
仅更新速度,如果球正朝着超出边界的方向移动。
public boolean update(Bounds bounds) {
Point pos = this.getCentre();
Vector velocity = this.getVelocity();
Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent());
image.setLayoutX(finalPos.getX());
image.setLayoutY(finalPos.getY());
setCentre(finalPos);
if ((finalPos.getX() <= 0 && velocity.getXComponent() < 0) || (finalPos.getX() + 2 * getRadius() >= bounds.maxX && velocity.getXComponent() > 0)) {
velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75);
}
if ((finalPos.getY() <= 0 && velocity.getYComponent() < 0) || (finalPos.getY() + 2 * getRadius() >= bounds.maxY && velocity.getYComponent() > 0)) {
velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75);
}
if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) {
System.out.println("Found it... line 24" + velocity + " " + getCentre());
return true;
}
return false;
}
首先防止球落在界外
public boolean update(Bounds bounds) {
Point pos = this.getCentre();
Vector velocity = this.getVelocity();
Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent());
boolean invertX = true;
if (finalPos.getX() <= 0) {
// mirror on left
finalPos.setX(-finalPos.getX());
} else if (finalPos.getX() + 2 * getRadius() >= bounds.maxX) {
// mirror on right
finalPos.setX(2 * (bounds.maxX - 2 * getRadius()) - finalPos.getX());
} else {
invertX = false;
}
if (invertX) {
velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75);
}
boolean invertY = true;
if (finalPos.getY() <= 0) {
// mirror on top
finalPos.setY(-finalPos.getY());
} else if (finalPos.getY() + 2 * getRadius() >= bounds.maxY) {
// mirror on bottom
finalPos.setY(2 * (bounds.maxY - 2 * getRadius()) - finalPos.getY());
} else {
invertY = false;
}
if (invertY) {
velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75);
}
setCentre(finalPos);
image.setLayoutX(finalPos.getX());
image.setLayoutY(finalPos.getY());
if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) {
System.out.println("Found it... line 24" + velocity + " " + getCentre());
return true;
}
return false;
}
我正在申请,需要一个在重力作用下弹跳的球。球弹得很好,但它永远不会停止。
我尝试打印停止点的坐标以及速度。这是其中一个案例的输出:
Found it... line 24. (0.00)i + (-0.01)j {14.14(0.79)} (-1.79, 651.57)
因此球停在高度 651.67 而边界是 600。这是另一种情况:
Found it... line 24. (0.00)i + (-0.01)j {14.14(0.79)} (-1.79, 1624.58)
代码如下:
GUI.java
import java.util.Timer;
import java.util.TimerTask;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.stage.Stage;
public class GUI extends Application {
@Override
public void start(Stage theStage) throws Exception {
theStage.setTitle("Bouncy Ball");
Group root = new Group();
Scene theScene = new Scene(root);
theStage.setScene(theScene);
Canvas canvas = new Canvas(750, 600);
root.getChildren().add(canvas);
CircleSprite sprite = new CircleSprite(30, new Point(50, 50));
root.getChildren().add(sprite.image);
sprite.setVelocity(new Vector(new Point(10, 10)));
theStage.show();
theStage.setOnCloseRequest(e -> {
System.exit(0);
});
AnimationTimer gameLoop = new AnimationTimer() {
@Override
public void handle(long now) {
if (sprite.update(new Bounds(700, 600))) {
this.stop();
}
}
};
gameLoop.start();
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Vector velocity = sprite.getVelocity();
velocity.setYComponent(velocity.getYComponent() + 1);
if (Math.abs(sprite.getVelocity().getYComponent()) <= 0.01
&& sprite.getCentre().getY() + 2 * sprite.getRadius() >= 500) {
System.out.println("Found it... line 55");
cancel();
}
}
}, 0, 100);
}
public static void main(String[] args) {
launch(args);
}
}
CircleSprite.java
public class CircleSprite extends Circle {
public javafx.scene.shape.Circle image;
public CircleSprite(long radius, Point centre) {
super(radius, centre);
image = new javafx.scene.shape.Circle(centre.getX(), centre.getY(), radius);
}
public boolean update(Bounds bounds) {
Point pos = this.getCentre();
Vector velocity = this.getVelocity();
Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent());
image.setLayoutX(finalPos.getX());
image.setLayoutY(finalPos.getY());
setCentre(finalPos);
if (finalPos.getX() <= 0 || finalPos.getX() + 2 * getRadius() >= bounds.maxX) {
velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75);
}
if (finalPos.getY() <= 0 || finalPos.getY() + 2 * getRadius() >= bounds.maxY) {
velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75);
}
if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) {
System.out.println("Found it... line 24" + velocity + " " + getCentre());
return true;
}
return false;
}
}
Bounds.java
public class Bounds {
public double maxX;
public double maxY;
public Bounds(double maxX, double maxY) {
this.maxX = maxX;
this.maxY = maxY;
}
}
Circle.java
public class Circle extends Shape {
private long radius;
private Point centre;
public Circle(long radius, Point centre) {
this.radius = radius;
this.centre = centre;
this.setVelocity(new Vector(new Point(0.0d, 0.0d), new Point(0, 0)));
this.setMass(0);
this.setRestitution(1);
this.setAcceleration(new Vector(new Point(0, 0), new Point(0, 0)));
}
/*
* Testing for whether or not two circles intersect is very simple: take the
* radii of the two circles and add them together, then check to see if this sum
* is greater than the distance between the two circles.
*/
public boolean isColliding(Circle a, Circle b) {
long dist = a.getRadius() + b.getRadius();
// In general multiplication is a much cheaper operation than taking the square
// root of a value.
return ((dist * dist) < (a.getCentre().getX() - b.getCentre().getX())
* (a.getCentre().getX() - b.getCentre().getX())
+ (a.getCentre().getY() - b.getCentre().getY()) * (a.getCentre().getY() - b.getCentre().getY()));
}
public long getRadius() {
return this.radius;
}
public void setRadius(long radius) {
this.radius = radius;
}
public Point getCentre() {
return this.centre;
}
public void setCentre(Point centre) {
this.centre = centre;
}
}
Shape.java
public class Shape {
private Vector velocity;
private Vector acceleration;
private long mass;
private double invMass;
private float restitution;
public Vector getAcceleration() {
return this.acceleration;
}
public void setAcceleration(Vector acceleration) {
this.acceleration = acceleration;
}
public long getMass() {
return this.mass;
}
public void setMass(long mass) {
this.mass = mass;
this.setInvMass(mass);
}
public Vector getVelocity() {
return this.velocity;
}
public void setVelocity(Vector velocity) {
this.velocity = velocity;
}
public double getInvMass() {
return this.invMass;
}
private void setInvMass(long mass) {
if (mass == 0) {
invMass = Long.MAX_VALUE;
return;
}
this.invMass = 1.0d / (double) mass;
}
public float getRestitution() {
return this.restitution;
}
public void setRestitution(float restitution) {
this.restitution = restitution;
}
}
Vector.java
public class Vector {
private Point p1;
private Point p2;
private double xComponent;
private double yComponent;
private double angle;
private double magnitude;
/*
* The constructor makes a vector crossing through two points p1 and p2.
*
* @param p1 The source point(x1, x2)
*/
public Vector(Point p1, Point p2) {
this.p1 = p1;
this.p2 = p2;
this.xComponent = this.p2.getX() - this.p1.getX();
this.yComponent = this.p2.getY() - this.p1.getY();
this.angle = Math.atan2(this.yComponent, this.xComponent);
this.magnitude = Math.sqrt(this.xComponent * this.xComponent + this.yComponent * this.yComponent);
}
public Vector(Point p2) {
Point p1 = new Point(0, 0);
this.p1 = p1;
this.p2 = p2;
this.xComponent = this.p2.getX() - this.p1.getX();
this.yComponent = this.p2.getY() - this.p1.getY();
this.angle = Math.atan2(this.yComponent, this.xComponent);
this.magnitude = Math.sqrt(this.xComponent * this.xComponent + this.yComponent * this.yComponent);
}
public Vector(double magnitude, Vector unitVector) {
scaledProduct(magnitude, unitVector);
}
private void scaledProduct(double magnitude, Vector unitVector) {
Point point = new Point(magnitude * unitVector.getXComponent(), magnitude * unitVector.getYComponent());
new Vector(point);
}
public static Vector scalarProduct(double magnitude, Vector unitVector) {
Point point = new Point(magnitude * unitVector.getXComponent(), magnitude * unitVector.getYComponent());
return new Vector(point);
}
public static double dotProduct(Vector v1, Vector v2) {
return (v1.xComponent * v2.xComponent + v1.yComponent * v2.yComponent);
}
public static Vector sum(Vector v1, Vector v2) {
return new Vector(new Point(v1.getXComponent() + v2.getXComponent(), v1.getYComponent() + v2.getYComponent()));
}
public static Vector difference(Vector from, Vector vector) {
return new Vector(new Point(from.getXComponent() - vector.getXComponent(),
from.getYComponent() - vector.getYComponent()));
}
public static double angleBetween(Vector v1, Vector v2) {
return Math.acos(Vector.dotProduct(v1, v2) / (v1.getMagnitude() * v2.getMagnitude()));
}
public Point getP1() {
return this.p1;
}
public void setP1(Point p1) {
this.p1 = p1;
}
public Point getP2() {
return this.p2;
}
public void setP2(Point p2) {
this.p2 = p2;
}
public double getXComponent() {
return this.xComponent;
}
public void setXComponent(double d) {
this.xComponent = d;
}
public double getYComponent() {
return this.yComponent;
}
public void setYComponent(double d) {
this.yComponent = d;
}
public double getAngle() {
return this.angle;
}
public void setAngle(double angle) {
this.angle = angle;
}
public double getMagnitude() {
return this.magnitude;
}
public void setMagnitude(double length) {
this.magnitude = length;
}
@Override
public boolean equals(Object v) {
Vector vector = (Vector) v;
return ((this.xComponent == vector.xComponent) && (this.yComponent == vector.yComponent));
}
@Override
public String toString() {
return String.format("(%.2f)i + (%.2f)j {%.2f(%.2f)}", this.xComponent, this.yComponent, this.magnitude,
this.angle);
}
}
Point.java
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public static double distance(Point p1, Point p2) {
return Math.sqrt(
(p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) + (p1.getY() - p2.getY()) * (p1.getY() - p2.getY()));
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
@Override
public String toString() {
return String.format("(%.2f, %.2f)", this.x, this.y);
}
}
代码有什么问题?我知道 GUI.java 和 CircleSprite.java 中的退出条件有问题,但不知道是什么。有两件事困扰着我:
1. Why is the height out of bound when it stops?
2. Why does the x goes negative?
这里发生的情况如下(仅考虑 x 维度;同样适用于 y):
球以v
的速度过界。您反转速度并降低其幅度。这可能会导致新速度不够高,无法在下一个更新步骤中回到边界,并且您再次反转速度以进一步降低速度。这导致球在边界外以越来越小的步幅来回移动,有效地给人以停止的印象。
值示例:
Frame 1
vx = -16
x = 1
Frame 2
vx = 12
x = -15
Frame 3
vx = -9
x = -3
Frame 4
vx = -6.75
x = -12
...
有两种方法可以解决这个问题:
仅更新速度,如果球正朝着超出边界的方向移动。
public boolean update(Bounds bounds) { Point pos = this.getCentre(); Vector velocity = this.getVelocity(); Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent()); image.setLayoutX(finalPos.getX()); image.setLayoutY(finalPos.getY()); setCentre(finalPos); if ((finalPos.getX() <= 0 && velocity.getXComponent() < 0) || (finalPos.getX() + 2 * getRadius() >= bounds.maxX && velocity.getXComponent() > 0)) { velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75); } if ((finalPos.getY() <= 0 && velocity.getYComponent() < 0) || (finalPos.getY() + 2 * getRadius() >= bounds.maxY && velocity.getYComponent() > 0)) { velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75); } if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) { System.out.println("Found it... line 24" + velocity + " " + getCentre()); return true; } return false; }
首先防止球落在界外
public boolean update(Bounds bounds) { Point pos = this.getCentre(); Vector velocity = this.getVelocity(); Point finalPos = new Point(pos.getX() + velocity.getXComponent(), pos.getY() + velocity.getYComponent()); boolean invertX = true; if (finalPos.getX() <= 0) { // mirror on left finalPos.setX(-finalPos.getX()); } else if (finalPos.getX() + 2 * getRadius() >= bounds.maxX) { // mirror on right finalPos.setX(2 * (bounds.maxX - 2 * getRadius()) - finalPos.getX()); } else { invertX = false; } if (invertX) { velocity.setXComponent(velocity.getXComponent() * (-1) * 0.75); } boolean invertY = true; if (finalPos.getY() <= 0) { // mirror on top finalPos.setY(-finalPos.getY()); } else if (finalPos.getY() + 2 * getRadius() >= bounds.maxY) { // mirror on bottom finalPos.setY(2 * (bounds.maxY - 2 * getRadius()) - finalPos.getY()); } else { invertY = false; } if (invertY) { velocity.setYComponent(velocity.getYComponent() * (-1) * 0.75); } setCentre(finalPos); image.setLayoutX(finalPos.getX()); image.setLayoutY(finalPos.getY()); if (Math.abs(velocity.getYComponent()) <= 0.01 && getCentre().getY() + 2 * getRadius() >= bounds.maxY) { System.out.println("Found it... line 24" + velocity + " " + getCentre()); return true; } return false; }