mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Documentation added to graphics classes.
#document
This commit is contained in:
@@ -10,7 +10,9 @@ import javafx.scene.transform.Rotate;
|
|||||||
import seng302.models.parsers.StreamParser;
|
import seng302.models.parsers.StreamParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by CJIRWIN on 25/04/2017.
|
* 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{
|
public class BoatGroup extends RaceObject{
|
||||||
|
|
||||||
@@ -18,36 +20,50 @@ public class BoatGroup extends RaceObject{
|
|||||||
private static final double TEAMNAME_Y_OFFSET = -15d;
|
private static final double TEAMNAME_Y_OFFSET = -15d;
|
||||||
private static final double VELOCITY_X_OFFSET = 10d;
|
private static final double VELOCITY_X_OFFSET = 10d;
|
||||||
private static final double VELOCITY_Y_OFFSET = -5d;
|
private static final double VELOCITY_Y_OFFSET = -5d;
|
||||||
private static final double VELOCITY_WAKE_RATIO = 2d;
|
|
||||||
private static final double BOAT_HEIGHT = 15d;
|
private static final double BOAT_HEIGHT = 15d;
|
||||||
private static final double BOAT_WIDTH = 10d;
|
private static final double BOAT_WIDTH = 10d;
|
||||||
private static final int LINE_INTERVAL = 180;
|
private static final int LINE_INTERVAL = 180;
|
||||||
private static double expectedUpdateInterval = 200;
|
private static double expectedUpdateInterval = 200;
|
||||||
private static int WAKE_FRAME_INTERVAL = 30;
|
|
||||||
private double framesForNewLine = 0;
|
private double framesForNewLine = 0;
|
||||||
private boolean destinationSet;
|
private boolean destinationSet;
|
||||||
private Point2D lastPoint;
|
private Point2D lastPoint;
|
||||||
private int wakeGenerationDelay;
|
private int wakeGenerationDelay;
|
||||||
|
|
||||||
private Boat boat;
|
private Boat boat;
|
||||||
private int wakeCounter = WAKE_FRAME_INTERVAL;
|
|
||||||
private Group lineGroup = new Group();
|
private Group lineGroup = new Group();
|
||||||
private Group wakeGroup = new Group();
|
|
||||||
private Polygon boatPoly;
|
private Polygon boatPoly;
|
||||||
private Text teamNameObject;
|
private Text teamNameObject;
|
||||||
private Text velocityObject;
|
private Text velocityObject;
|
||||||
private Wake wake;
|
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){
|
public BoatGroup (Boat boat, Color color){
|
||||||
this.boat = boat;
|
this.boat = boat;
|
||||||
initChildren(color);
|
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)
|
public BoatGroup (Boat boat, Color color, double... points)
|
||||||
{
|
{
|
||||||
initChildren(color, points);
|
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) {
|
private void initChildren (Color color, double... points) {
|
||||||
boatPoly = new Polygon(points);
|
boatPoly = new Polygon(points);
|
||||||
boatPoly.setFill(color);
|
boatPoly.setFill(color);
|
||||||
@@ -64,16 +80,20 @@ public class BoatGroup extends RaceObject{
|
|||||||
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
||||||
destinationSet = false;
|
destinationSet = false;
|
||||||
|
|
||||||
wake = new Wake(0, 0);
|
wake = new Wake(0, -BOAT_HEIGHT);
|
||||||
wakeGenerationDelay = wake.numWakes;
|
wakeGenerationDelay = wake.numWakes;
|
||||||
super.getChildren().addAll(teamNameObject, velocityObject, boatPoly);
|
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) {
|
private void initChildren (Color color) {
|
||||||
initChildren(color,
|
initChildren(color,
|
||||||
-BOAT_WIDTH / 2, BOAT_HEIGHT,
|
-BOAT_WIDTH / 2, BOAT_HEIGHT / 2,
|
||||||
0.0, 0.0,
|
0.0, -BOAT_HEIGHT / 2,
|
||||||
BOAT_WIDTH / 2, BOAT_HEIGHT);
|
BOAT_WIDTH / 2, BOAT_HEIGHT / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,12 +117,18 @@ public class BoatGroup extends RaceObject{
|
|||||||
* Moves the boat and its children annotations to coordinates specified
|
* Moves the boat and its children annotations to coordinates specified
|
||||||
* @param x The X coordinate to move the boat to
|
* @param x The X coordinate to move the boat to
|
||||||
* @param y The Y 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) {
|
public void moveTo (double x, double y, double rotation) {
|
||||||
rotateTo(rotation);
|
rotateTo(rotation);
|
||||||
moveTo(x, y);
|
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) {
|
public void moveTo (double x, double y) {
|
||||||
boatPoly.setLayoutX(x);
|
boatPoly.setLayoutX(x);
|
||||||
boatPoly.setLayoutY(y);
|
boatPoly.setLayoutY(y);
|
||||||
@@ -115,10 +141,15 @@ public class BoatGroup extends RaceObject{
|
|||||||
wake.rotate(currentRotation);
|
wake.rotate(currentRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the position of all graphics in the BoatGroup based off of the given time interval.
|
||||||
|
* @param timeInterval The interval, in microseconds, the boat should update it's position based on.
|
||||||
|
*/
|
||||||
public void updatePosition (long timeInterval) {
|
public void updatePosition (long timeInterval) {
|
||||||
|
//Calculate the movement of the boat.
|
||||||
double dx = pixelVelocityX * timeInterval;
|
double dx = pixelVelocityX * timeInterval;
|
||||||
double dy = pixelVelocityY * timeInterval;
|
double dy = pixelVelocityY * timeInterval;
|
||||||
double rotation = 0d;
|
double rotation = rotationalVelocity * timeInterval;
|
||||||
|
|
||||||
moveGroupBy(dx, dy, rotation);
|
moveGroupBy(dx, dy, rotation);
|
||||||
|
|
||||||
@@ -138,7 +169,7 @@ public class BoatGroup extends RaceObject{
|
|||||||
if (destinationSet){
|
if (destinationSet){
|
||||||
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY());
|
||||||
}
|
}
|
||||||
if (lineGroup.getChildren().size() > 100)
|
if (lineGroup.getChildren().size() > 60)
|
||||||
lineGroup.getChildren().remove(0);
|
lineGroup.getChildren().remove(0);
|
||||||
}
|
}
|
||||||
wake.updatePosition(timeInterval);
|
wake.updatePosition(timeInterval);
|
||||||
@@ -148,11 +179,25 @@ public class BoatGroup extends RaceObject{
|
|||||||
destinationSet = true;
|
destinationSet = true;
|
||||||
boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
|
boat.setVelocity(StreamParser.boatSpeeds.get((long)boat.getId()));
|
||||||
if (hasRaceId(raceIds)) {
|
if (hasRaceId(raceIds)) {
|
||||||
this.pixelVelocityX = (newXValue - boatPoly.getLayoutX()) / expectedUpdateInterval;
|
double dx = newXValue - boatPoly.getLayoutX();
|
||||||
this.pixelVelocityY = (newYValue - boatPoly.getLayoutY()) / expectedUpdateInterval;
|
if ((dx > 0 && pixelVelocityX < 0) || (dx < 0 && pixelVelocityX > 0)) {
|
||||||
this.rotationalGoal = rotation;
|
pixelVelocityX = 0;
|
||||||
|
} else {
|
||||||
|
pixelVelocityX = dx / expectedUpdateInterval;
|
||||||
|
}
|
||||||
|
double dy = newYValue - boatPoly.getLayoutY();
|
||||||
|
if ((dy > 0 && pixelVelocityY < 0) || (dy < 0 && pixelVelocityY > 0)) {
|
||||||
|
pixelVelocityY = 0;
|
||||||
|
} else {
|
||||||
|
pixelVelocityY = dy / expectedUpdateInterval;
|
||||||
|
}
|
||||||
|
// this.pixelVelocityX = (newXValue - boatPoly.getLayoutX()) / expectedUpdateInterval;
|
||||||
|
// this.pixelVelocityY = (newYValue - boatPoly.getLayoutY()) / expectedUpdateInterval;
|
||||||
|
rotationalGoal = rotation;
|
||||||
calculateRotationalVelocity();
|
calculateRotationalVelocity();
|
||||||
rotateTo(rotation);
|
if (Math.abs(rotationalVelocity) > 0.00003)
|
||||||
|
rotationalVelocity = 0;
|
||||||
|
|
||||||
if (wakeGenerationDelay > 0) {
|
if (wakeGenerationDelay > 0) {
|
||||||
wake.rotate(rotationalGoal);
|
wake.rotate(rotationalGoal);
|
||||||
wakeGenerationDelay--;
|
wakeGenerationDelay--;
|
||||||
@@ -177,29 +222,12 @@ public class BoatGroup extends RaceObject{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resizeWake(){
|
|
||||||
velocityObject.setText(String.valueOf(boat.getVelocity()));
|
|
||||||
super.getChildren().remove(wakePoly);
|
|
||||||
wakePoly = new Polygon(
|
|
||||||
5.0,0.0,
|
|
||||||
10.0, boat.getVelocity() * VELOCITY_WAKE_RATIO,
|
|
||||||
0.0, boat.getVelocity() * VELOCITY_WAKE_RATIO
|
|
||||||
);
|
|
||||||
wakePoly.setLayoutX(boatPoly.getLayoutX());
|
|
||||||
wakePoly.setLayoutY(boatPoly.getLayoutY());
|
|
||||||
wakePoly.setFill(Color.DARKBLUE);
|
|
||||||
super.getChildren().add(wakePoly);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rotateTo (double rotation) {
|
public void rotateTo (double rotation) {
|
||||||
currentRotation = rotation;
|
currentRotation = rotation;
|
||||||
boatPoly.getTransforms().clear();
|
boatPoly.getTransforms().clear();
|
||||||
boatPoly.getTransforms().add(new Rotate(rotation));
|
boatPoly.getTransforms().add(new Rotate(rotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void forceRotation () {
|
public void forceRotation () {
|
||||||
rotateTo (rotationalGoal);
|
rotateTo (rotationalGoal);
|
||||||
wake.rotate(rotationalGoal);
|
wake.rotate(rotationalGoal);
|
||||||
|
|||||||
@@ -1,51 +1,97 @@
|
|||||||
package seng302.models;
|
package seng302.models;
|
||||||
|
|
||||||
|
import javafx.scene.Group;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.shape.Arc;
|
import javafx.scene.shape.Arc;
|
||||||
import javafx.scene.shape.ArcType;
|
import javafx.scene.shape.ArcType;
|
||||||
import javafx.scene.transform.Rotate;
|
import javafx.scene.transform.Rotate;
|
||||||
import javafx.scene.transform.Translate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by CJIRWIN on 27/04/2017.
|
* By default wake is a group containing 5 arcs. Each arc starts from the same point. Each arc is larger and more
|
||||||
|
* transparent than the last. On calling updatePositions() arcs rotate at velocities given by setRotationalVelocity().
|
||||||
|
* The larger and more transparent an arc is the longer the delay before it rotates at the latest velocity. It is
|
||||||
|
* assumed that rotationalVelocities() are set regularly as wakes do not stop rotating and an array of velocities needs
|
||||||
|
* to be populated for the class to work as expected.
|
||||||
*/
|
*/
|
||||||
class Wake extends Arc {
|
class Wake extends Group {
|
||||||
|
|
||||||
private static int VELOCITY_SCALE_FACTOR = 3;
|
final int numWakes = 5;
|
||||||
private static int MAX_LIFESPAN = 210;
|
private double[] velocities = new double[13];
|
||||||
private static double LIFESPAN_PER_FRAME = 1.0 / MAX_LIFESPAN;
|
private Arc[] arcs = new Arc[numWakes];
|
||||||
//private static double LENGTH_PER_FRAME = 120 / MAX_LIFESPAN;
|
private double[] rotations = new double[numWakes];
|
||||||
private static double LENGTH_PER_FRAME = 0.25;
|
private int[] velocityIndices = new int[numWakes];
|
||||||
|
private double sum = 0;
|
||||||
|
|
||||||
private double velocityX;
|
/**
|
||||||
private double velocityY;
|
* Create a wake at the given location.
|
||||||
private double opacity;
|
* @param startingX x location where the tip of wake arcs will be.
|
||||||
private int lifespan = MAX_LIFESPAN;
|
* @param startingY y location where the tip of wake arcs will be.
|
||||||
|
*/
|
||||||
Wake (double startingX, double startingY, double velocityX, double velocityY, double rotation) {
|
Wake(double startingX, double startingY) {
|
||||||
super(startingX, startingY, 20, 30, 180, 0);
|
super.setLayoutX(startingX);
|
||||||
//super.setFill(Color.BLUE);
|
super.setLayoutY(startingY);
|
||||||
super.setStroke(Color.DEEPSKYBLUE);
|
Arc arc;
|
||||||
super.setType(ArcType.OPEN);
|
for (int i = 0; i < numWakes; i++) {
|
||||||
super.setFill(new Color(0, 0, 0 ,0));
|
//Default triangle is -110 deg out of phase with a default wake and has angle of 40 deg.
|
||||||
super.setStrokeWidth(2.0);
|
arc = new Arc(0,0,0,0,-110,40);
|
||||||
super.getTransforms().add(new Rotate(rotation - 270, startingX + 20, startingY + 20));
|
//Opacity increases from 0.5 -> 0 evenly over the 5 wake arcs.
|
||||||
// this.velocityX = -velocityX;
|
arc.setFill(new Color(0.18, 0.7, 1.0, 0.50 + -0.1 * i));
|
||||||
// this.velocityY = -velocityY;
|
arc.setType(ArcType.ROUND);
|
||||||
this.velocityX = 0;
|
arcs[i] = arc;
|
||||||
this.velocityY = 0;
|
}
|
||||||
|
super.getChildren().addAll(arcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean updatePosition (double timeInterval) {
|
/**
|
||||||
lifespan--;
|
* Sets the rotationalVelocity of each arc. Each arc is 3 velocities behind the next smallest arc. The smallest uses
|
||||||
//super.setOpacity(LIFESPAN_PER_FRAME * lifespan * super.getOpacity());
|
* the latest given velocity.
|
||||||
//opacity = LIFESPAN_PER_FRAME * lifespan * opacity;
|
* @param rotationalVelocity The rotationalVelocity the wake should move at.
|
||||||
//super.setFill(new Color(0.0f, 0.0f, 1.0f, opacity));
|
*/
|
||||||
super.setLayoutX(super.getLayoutX() + velocityX * timeInterval);
|
void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocityX, double velocityY) {
|
||||||
super.setLayoutY(super.getLayoutY() + velocityY * timeInterval);
|
sum -= Math.abs(velocities[velocityIndices[0]]);
|
||||||
super.setStartAngle(super.getStartAngle() - LENGTH_PER_FRAME);
|
sum += Math.abs(rotationalVelocity);
|
||||||
super.setLength(super.getLength() + LENGTH_PER_FRAME * 2);
|
if (sum < 0.00003)
|
||||||
return lifespan < 0;
|
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.
|
||||||
|
|
||||||
|
//Update the index of the array of recent velocities that each wake uses. Each wake is 3 velocities behind the
|
||||||
|
//next smallest wake.
|
||||||
|
velocityIndices[0] = (13 + (velocityIndices[0] - 1) % 13) % 13;
|
||||||
|
velocities[velocityIndices[0]] = rotationalVelocity;
|
||||||
|
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;
|
||||||
|
for (Arc arc :arcs) {
|
||||||
|
double rad = Math.min(baseRad + 5 * scaleFactor, baseRad + 15);
|
||||||
|
arc.setRadiusX(rad);
|
||||||
|
arc.setRadiusY(rad);
|
||||||
|
baseRad += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arcs rotate based on the distance they would have travelled over the supplied time interval.
|
||||||
|
* @param timeInterval the time interval, in microseconds, that the wake should move.
|
||||||
|
*/
|
||||||
|
void updatePosition (long timeInterval) {
|
||||||
|
for (int i = 0; i < numWakes; i++) {
|
||||||
|
rotations[i] = rotations[i] + velocities[velocityIndices[i]] * timeInterval;
|
||||||
|
arcs[i].getTransforms().setAll(new Rotate(rotations[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate all wakes to the given rotation.
|
||||||
|
* @param rotation the from north angle in degrees to rotate to.
|
||||||
|
*/
|
||||||
|
void rotate (double rotation) {
|
||||||
|
for (int i = 0; i < arcs.length; i++) {
|
||||||
|
rotations[i] = rotation;
|
||||||
|
arcs[i].getTransforms().setAll(new Rotate(rotation));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user