Boat trials and wakes now work with both fast and slow data sets.

Instead of fixed, hard coded thresholds and scale factors dynamically changing values
that scale with the onscreen movement are used to determine how graphical objects
are drawn.

#implement #story[816]
This commit is contained in:
Kusal Ekanayake
2017-05-01 16:41:58 +12:00
parent c80cff87f7
commit 5fe330bfbb
5 changed files with 61 additions and 34 deletions
+39 -16
View File
@@ -22,11 +22,11 @@ public class BoatGroup extends RaceObject{
private static final double VELOCITY_Y_OFFSET = -5d;
private static final double BOAT_HEIGHT = 15d;
private static final double BOAT_WIDTH = 10d;
private static final int LINE_INTERVAL = 30;
private double framesForNewLine = 0;
private static double expectedUpdateInterval = 200;
private boolean destinationSet;
private Point2D lastPoint;
private int wakeGenerationDelay;
private int wakeGenerationDelay = 10;
private double distanceTravelled;
private Boat boat;
private Group lineGroup = new Group();
@@ -81,7 +81,6 @@ public class BoatGroup extends RaceObject{
destinationSet = false;
wake = new Wake(0, -BOAT_HEIGHT);
wakeGenerationDelay = wake.numWakes;
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
}
@@ -150,10 +149,11 @@ public class BoatGroup extends RaceObject{
double dx = pixelVelocityX * timeInterval;
double dy = pixelVelocityY * timeInterval;
double rotation = rotationalVelocity * timeInterval;
distanceTravelled += Math.abs(dx) + Math.abs(dy);
moveGroupBy(dx, dy, rotation);
if (framesForNewLine-- == 0) {
framesForNewLine = LINE_INTERVAL;
//Draw a new section of the trail every 20 pixels of movement.
if (distanceTravelled > 20) {
distanceTravelled = 0;
if (lastPoint != null) {
Line l = new Line(
lastPoint.getX(),
@@ -161,19 +161,24 @@ public class BoatGroup extends RaceObject{
boatPoly.getLayoutX(),
boatPoly.getLayoutY()
);
l.getStrokeDashArray().setAll(4d, 6d);
l.getStrokeDashArray().setAll(3d, 7d);
l.setStroke(boatPoly.getFill());
lineGroup.getChildren().add(l);
}
if (destinationSet){
if (destinationSet){ //Only begin drawing after the first destination is set
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
}
if (lineGroup.getChildren().size() > 60)
lineGroup.getChildren().remove(0);
}
wake.updatePosition(timeInterval);
}
/**
* Sets the destination of the boat and the headng it should have once it reaches
* @param newXValue
* @param newYValue
* @param rotation Rotation to move graphics to.
* @param raceIds RaceID of the object to move.
*/
public void setDestination (double newXValue, double newYValue, double rotation, int... raceIds) {
if (hasRaceId(raceIds)) {
destinationSet = true;
@@ -187,19 +192,37 @@ public class BoatGroup extends RaceObject{
pixelVelocityX = dx / expectedUpdateInterval;
}
double dy = newYValue - boatPoly.getLayoutY();
if ((dy > 0 && pixelVelocityY < 0) || (dy < 0 && pixelVelocityY > 0)) {
pixelVelocityY = 0;
} else {
pixelVelocityY = dy / expectedUpdateInterval;
//Check movement is reasonable. Assumes a 1000 * 1000 canvas
if (Math.abs(dx) > 50 || Math.abs(dy) > 50) {
// System.out.println("dx = " + dx);
// System.out.println("dy = " + dy);
dx = 0;
dy = 0;
moveTo(newXValue, newYValue);
}
//Slight delay on changing X/Y direction that could help jitter. Disabled since there was an issue with
//packets that might be causing it.
// if ((dx > 0 && pixelVelocityX < 0) || (dx < 0 && pixelVelocityX > 0)) {
// pixelVelocityX = 0;
// } else {
// pixelVelocityX = dx / expectedUpdateInterval;
// }
// if ((dy > 0 && pixelVelocityY < 0) || (dy < 0 && pixelVelocityY > 0)) {
// pixelVelocityY = 0;
// } else {
// pixelVelocityY = dy / expectedUpdateInterval;
// }
pixelVelocityX = dx / expectedUpdateInterval;
pixelVelocityY = dy / expectedUpdateInterval;
rotationalGoal = rotation;
calculateRotationalVelocity();
if (wakeGenerationDelay > 0) {
wake.rotate(rotationalGoal);
wakeGenerationDelay--;
} else {
wake.setRotationalVelocity(rotationalVelocity, currentRotation, pixelVelocityX, pixelVelocityY);
wake.setRotationalVelocity(rotationalVelocity, currentRotation, boat.getVelocity());
}
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
}
}
+17 -12
View File
@@ -15,12 +15,13 @@ import javafx.scene.transform.Rotate;
*/
class Wake extends Group {
final int numWakes = 5;
private int numWakes = 5;
private double[] velocities = new double[13];
private Arc[] arcs = new Arc[numWakes];
private double[] rotations = new double[numWakes];
private int[] velocityIndices = new int[numWakes];
private double sum = 0;
private static double max;
/**
* Create a wake at the given location.
@@ -46,15 +47,19 @@ class Wake extends Group {
* Sets the rotationalVelocity of each arc. Each arc is 3 velocities behind the next smallest arc. The smallest uses
* the latest given velocity.
* @param rotationalVelocity The rotationalVelocity the wake should move at.
* @param rotationGoal Where the wake will rotate to if the wake is calculated to be on a straight section. This is
* used to prevent desynchronisation with the Boat polygon.
* @param velocity The real world velocity of the boat in m/s.
*/
void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocityX, double velocityY) {
if (Math.abs(rotationalVelocity) > 0.5) {
rotationalVelocity = 0;
}
void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocity) {
// if (Math.abs(rotationalVelocity) > 0.5) {
// rotationalVelocity = 0;
// }
sum -= Math.abs(velocities[(velocityIndices[0] + 10) % 13]);
sum += Math.abs(rotationalVelocity);
System.out.println("sum = " + sum);
if (sum < 0.9)
// System.out.println("sum = " + sum);
max = Math.max(max, rotationalVelocity);
if (sum < max)
rotate (rotationGoal); //In relatively straight segments the wake snaps to match the boats current position.
//This stops the wake from eventually becoming out of sync with the boat.
@@ -65,14 +70,14 @@ class Wake extends Group {
for (int i = 1; i < numWakes; i++)
velocityIndices[i] = (velocityIndices[0] + 3 * i) % 13;
//Scale wakes based on velocity. Assumes boats are always moving at a decent pace.
double scaleFactor = Math.abs(Math.log10(Math.abs(velocityX) + Math.abs(velocityY)));
double baseRad = 25;
//Scale wakes based on velocity.
double baseRad = 20;
double rad;
for (Arc arc :arcs) {
double rad = Math.min(baseRad + 5 * scaleFactor, baseRad + 15);
rad = baseRad + velocity;
arc.setRadiusX(rad);
arc.setRadiusY(rad);
baseRad += 10;
baseRad += 5 + (velocity / 2);
}
}
@@ -142,13 +142,13 @@ public class MarkGroup extends RaceObject {
if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() ||
nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY())
nodePixelVelocitiesX[0] = 0;
else
else if (nodePixelVelocitiesX[0] != 0)
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[0] * timeInterval);
if (nodePixelVelocitiesY[0] > 0 && markCircle.getCenterY() > nodeDestinations[0].getY() ||
nodePixelVelocitiesY[0] < 0 && markCircle.getCenterY() < nodeDestinations[0].getY())
nodePixelVelocitiesY[0] = 0;
else
else if (nodePixelVelocitiesY[0] != 0)
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[0] * timeInterval);
if (mainMark.getMarkType() != MarkType.SINGLE_MARK) {
@@ -162,13 +162,13 @@ public class MarkGroup extends RaceObject {
if (nodePixelVelocitiesX[1] > 0 && markCircle.getCenterX() >= nodeDestinations[1].getX() ||
nodePixelVelocitiesX[1] < 0 && markCircle.getCenterX() <= nodeDestinations[1].getX())
nodePixelVelocitiesX[1] = 0;
else
else if (nodePixelVelocitiesX[1] != 0)
markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[1] * timeInterval);
if (nodePixelVelocitiesY[1] > 0 && markCircle.getCenterY() > nodeDestinations[1].getY() ||
nodePixelVelocitiesY[1] < 0 && markCircle.getCenterY() < nodeDestinations[1].getY())
nodePixelVelocitiesY[1] = 0;
else
else if (nodePixelVelocitiesY[1] != 0)
markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[1] * timeInterval);
line.setEndX(markCircle.getCenterX());
line.setEndY(markCircle.getCenterY());