mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
5fe330bfbb
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]
311 lines
12 KiB
Java
311 lines
12 KiB
Java
package seng302.models;
|
|
|
|
import javafx.geometry.Point2D;
|
|
import javafx.scene.Group;
|
|
import javafx.scene.paint.Color;
|
|
import javafx.scene.shape.Line;
|
|
import javafx.scene.shape.Polygon;
|
|
import javafx.scene.text.Text;
|
|
import javafx.scene.transform.Rotate;
|
|
import seng302.models.parsers.StreamParser;
|
|
|
|
/**
|
|
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat.
|
|
* It contains a single polygon for the boat, a group of lines to show it's path, a wake object and two text labels to
|
|
* annotate the boat teams name and the boats velocity.
|
|
*/
|
|
public class BoatGroup extends RaceObject{
|
|
|
|
private static final double TEAMNAME_X_OFFSET = 10d;
|
|
private static final double TEAMNAME_Y_OFFSET = -15d;
|
|
private static final double VELOCITY_X_OFFSET = 10d;
|
|
private static final double VELOCITY_Y_OFFSET = -5d;
|
|
private static final double BOAT_HEIGHT = 15d;
|
|
private static final double BOAT_WIDTH = 10d;
|
|
private static double expectedUpdateInterval = 200;
|
|
private boolean destinationSet;
|
|
private Point2D lastPoint;
|
|
private int wakeGenerationDelay = 10;
|
|
private double distanceTravelled;
|
|
|
|
private Boat boat;
|
|
private Group lineGroup = new Group();
|
|
private Polygon boatPoly;
|
|
private Text teamNameObject;
|
|
private Text velocityObject;
|
|
private Wake wake;
|
|
|
|
/**
|
|
* Creates a BoatGroup with the default triangular boat polygon.
|
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which
|
|
* BoatGroup to update.
|
|
* @param color The colour of the boat polygon and the trailing line.
|
|
*/
|
|
public BoatGroup (Boat boat, Color color){
|
|
this.boat = boat;
|
|
initChildren(color);
|
|
}
|
|
|
|
/**
|
|
* Creates a BoatGroup with the boat being the default polygon. The head of the boat should be at point (0,0).
|
|
* @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which
|
|
* BoatGroup to update.
|
|
* @param color The colour of the boat polygon and the trailing line.
|
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon.
|
|
*/
|
|
public BoatGroup (Boat boat, Color color, double... points)
|
|
{
|
|
this.boat = boat;
|
|
initChildren(color, points);
|
|
}
|
|
|
|
/**
|
|
* Creates the javafx objects that will be the in the group by default.
|
|
* @param color The colour of the boat polygon and the trailing line.
|
|
* @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon.
|
|
*/
|
|
private void initChildren (Color color, double... points) {
|
|
boatPoly = new Polygon(points);
|
|
boatPoly.setFill(color);
|
|
|
|
teamNameObject = new Text(boat.getShortName());
|
|
velocityObject = new Text(String.valueOf(boat.getVelocity()));
|
|
|
|
teamNameObject.setX(TEAMNAME_X_OFFSET);
|
|
teamNameObject.setY(TEAMNAME_Y_OFFSET);
|
|
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
|
|
|
|
velocityObject.setX(VELOCITY_X_OFFSET);
|
|
velocityObject.setY(VELOCITY_Y_OFFSET);
|
|
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
|
destinationSet = false;
|
|
|
|
wake = new Wake(0, -BOAT_HEIGHT);
|
|
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
|
|
}
|
|
|
|
/**
|
|
* Creates the javafx objects that will be the in the group by default.
|
|
* @param color The colour of the boat polygon and the trailing line.
|
|
*/
|
|
private void initChildren (Color color) {
|
|
initChildren(color,
|
|
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
|
0.0, -BOAT_HEIGHT / 2,
|
|
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
|
}
|
|
|
|
/**
|
|
* Moves the boat and its children annotations from its current coordinates by specified amounts.
|
|
* @param dx The amount to move the X coordinate by
|
|
* @param dy The amount to move the Y coordinate by
|
|
*/
|
|
public void moveGroupBy(double dx, double dy, double rotation) {
|
|
boatPoly.setLayoutX(boatPoly.getLayoutX() + dx);
|
|
boatPoly.setLayoutY(boatPoly.getLayoutY() + dy);
|
|
teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx);
|
|
teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy);
|
|
velocityObject.setLayoutX(velocityObject.getLayoutX() + dx);
|
|
velocityObject.setLayoutY(velocityObject.getLayoutY() + dy);
|
|
wake.setLayoutX(wake.getLayoutX() + dx);
|
|
wake.setLayoutY(wake.getLayoutY() + dy);
|
|
rotateTo(rotation + currentRotation);
|
|
}
|
|
|
|
/**
|
|
* Moves the boat and its children annotations to coordinates specified
|
|
* @param x The X coordinate to move the boat to
|
|
* @param y The Y coordinate to move the boat to
|
|
* @param rotation The heading in degrees from north the boat should rotate to.
|
|
*/
|
|
public void moveTo (double x, double y, double rotation) {
|
|
rotateTo(rotation);
|
|
moveTo(x, y);
|
|
}
|
|
|
|
/**
|
|
* Moves the boat and its children annotations to coordinates specified
|
|
* @param x The X coordinate to move the boat to
|
|
* @param y The Y coordinate to move the boat to
|
|
*/
|
|
public void moveTo (double x, double y) {
|
|
boatPoly.setLayoutX(x);
|
|
boatPoly.setLayoutY(y);
|
|
teamNameObject.setLayoutX(x);
|
|
teamNameObject.setLayoutY(y);
|
|
velocityObject.setLayoutX(x);
|
|
velocityObject.setLayoutY(y);
|
|
wake.setLayoutX(x);
|
|
wake.setLayoutY(y);
|
|
wake.rotate(currentRotation);
|
|
}
|
|
|
|
/**
|
|
* Updates the position of all graphics in the BoatGroup based off of the given time interval.
|
|
* @param timeInterval The interval, in milliseconds, the boat should update it's position based on.
|
|
*/
|
|
public void updatePosition (long timeInterval) {
|
|
//Calculate the movement of the boat.
|
|
double dx = pixelVelocityX * timeInterval;
|
|
double dy = pixelVelocityY * timeInterval;
|
|
double rotation = rotationalVelocity * timeInterval;
|
|
distanceTravelled += Math.abs(dx) + Math.abs(dy);
|
|
moveGroupBy(dx, dy, rotation);
|
|
//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(),
|
|
lastPoint.getY(),
|
|
boatPoly.getLayoutX(),
|
|
boatPoly.getLayoutY()
|
|
);
|
|
l.getStrokeDashArray().setAll(3d, 7d);
|
|
l.setStroke(boatPoly.getFill());
|
|
lineGroup.getChildren().add(l);
|
|
}
|
|
if (destinationSet){ //Only begin drawing after the first destination is set
|
|
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
|
}
|
|
}
|
|
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;
|
|
boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
|
|
if (currentRotation < 0)
|
|
currentRotation = 360 - currentRotation;
|
|
double dx = newXValue - boatPoly.getLayoutX();
|
|
if ((dx > 0 && pixelVelocityX < 0) || (dx < 0 && pixelVelocityX > 0)) {
|
|
pixelVelocityX = 0;
|
|
} else {
|
|
pixelVelocityX = dx / expectedUpdateInterval;
|
|
}
|
|
double dy = newYValue - boatPoly.getLayoutY();
|
|
//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, boat.getVelocity());
|
|
}
|
|
velocityObject.setText(String.format("%.2f m/s", boat.getVelocity()));
|
|
}
|
|
}
|
|
|
|
public void setDestination (double newXValue, double newYValue, int... raceIDs) {
|
|
destinationSet = true;
|
|
|
|
if (hasRaceId(raceIDs)) {
|
|
double rotation = Math.abs(
|
|
Math.toDegrees(
|
|
Math.atan(
|
|
(newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX())
|
|
)
|
|
)
|
|
);
|
|
setDestination(newXValue, newYValue, rotation, raceIDs);
|
|
}
|
|
}
|
|
|
|
public void rotateTo (double rotation) {
|
|
currentRotation = rotation;
|
|
boatPoly.getTransforms().clear();
|
|
boatPoly.getTransforms().add(new Rotate(rotation));
|
|
}
|
|
|
|
public void forceRotation () {
|
|
rotateTo (rotationalGoal);
|
|
wake.rotate(rotationalGoal);
|
|
}
|
|
|
|
public void setTeamNameObjectVisible(Boolean visible) {
|
|
teamNameObject.setVisible(visible);
|
|
}
|
|
|
|
public void setVelocityObjectVisible(Boolean visible) {
|
|
velocityObject.setVisible(visible);
|
|
}
|
|
|
|
public void setLineGroupVisible(Boolean visible) {
|
|
lineGroup.setVisible(visible);
|
|
}
|
|
|
|
public void setWakeVisible(Boolean visible) {
|
|
wake.setVisible(visible);
|
|
}
|
|
|
|
public Boat getBoat() {
|
|
return boat;
|
|
}
|
|
|
|
/**
|
|
* Returns true if this BoatGroup contains at least one of the given IDs.
|
|
*
|
|
* @param raceIds The ID's to check the BoatGroup for.
|
|
* @return True if the BoatGroup contains at east one of the given IDs, false otherwise.
|
|
*/
|
|
public boolean hasRaceId (int... raceIds) {
|
|
for (int id : raceIds) {
|
|
if (id == boat.getId())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat.
|
|
*
|
|
* @return An array containing all ID's associated with this RaceObject.
|
|
*/
|
|
public int[] getRaceIds () {
|
|
return new int[] {boat.getId()};
|
|
}
|
|
|
|
/**
|
|
* Due to javaFX limitations annotations associated with a boat that you want to appear below all boats in the
|
|
* Z-axis need to be pulled out of the BoatGroup and added to the parent group of the BoatGroups. This function
|
|
* returns these annotations as a group.
|
|
*
|
|
* @return A group containing low priority annotations.
|
|
*/
|
|
public Group getLowPriorityAnnotations () {
|
|
Group group = new Group();
|
|
group.getChildren().addAll(wake, lineGroup);
|
|
return group;
|
|
}
|
|
}
|