diff --git a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java index c3046d18..48d19d09 100644 --- a/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java +++ b/racevisionGame/src/main/java/visualiser/Commands/VisualiserRaceCommands/BoatCollisionCommand.java @@ -3,6 +3,8 @@ package visualiser.Commands.VisualiserRaceCommands; import javafx.scene.media.AudioClip; import mock.model.commandFactory.Command; import network.Messages.YachtEvent; +import shared.exceptions.BoatNotFoundException; +import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceState; /** @@ -34,6 +36,11 @@ public class BoatCollisionCommand implements Command { sound.play(); } - //System.out.println("Collision command executed!"); + try { + VisualiserBoat boat = visualiserRace.getBoat(yachtEvent.getSourceID()); + boat.setHasCollided(true); + } catch (BoatNotFoundException e) { + e.printStackTrace(); + } } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java index a7577538..78f5e736 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceViewController.java @@ -21,10 +21,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.paint.Material; import javafx.scene.paint.PhongMaterial; -import javafx.scene.shape.Box; -import javafx.scene.shape.MeshView; -import javafx.scene.shape.Shape3D; -import javafx.scene.shape.Sphere; +import javafx.scene.shape.*; import javafx.scene.transform.Translate; import javafx.util.Callback; import network.Messages.Enums.RaceStatusEnum; @@ -72,8 +69,14 @@ public class RaceViewController extends Controller { private View3D view3D; private ObservableList viewSubjects; + /** + * Arrow pointing to next mark in third person + */ private Subject3D nextMarkArrow; - private ChangeListener pointToMark; + /** + * Animation loop for rotating mark arrow + */ + private AnimationTimer pointToMark; // note: it says it's not used but it is! do not remove :) private @FXML ArrowController arrowController; @@ -313,8 +316,12 @@ public class RaceViewController extends Controller { if(nextMark.getMark2() != null) { view3D.getShape(nextMark.getMark2().getSourceID()).setMaterial(markColor); } + Subject3D shockwave = new Shockwave(10); + + viewSubjects.add(shockwave); boat.legProperty().addListener((o, prev, curr) -> swapColours(curr)); + boat.hasCollidedProperty().addListener((o, prev, curr) -> showCollision(boatModel, shockwave)); } // Fix initial bird's-eye position view3D.updatePivot(new Translate(250, 0, 210)); @@ -372,22 +379,47 @@ public class RaceViewController extends Controller { }); } + private void showCollision(Subject3D boat, Subject3D shockwave) { + AnimationTimer shockFront = new AnimationTimer() { + double opacity = 1; + + @Override + public void handle(long now) { + shockwave.setX(boat.getPosition().getX()); + shockwave.setY(boat.getPosition().getY()); + shockwave.setZ(boat.getPosition().getZ()); + + if(opacity <= 0) { + shockwave.getMesh().setMaterial(new PhongMaterial(new Color(1,0,0,0))); + this.stop(); + } + else { + shockwave.getMesh().setMaterial(new PhongMaterial(new Color(1,0,0,opacity))); + opacity -= 0.1; + } + } + }; + shockFront.start(); + } + private void addThirdPersonAnnotations(Subject3D subject3D) { viewSubjects.add(nextMarkArrow); try { VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID()); - this.pointToMark = (o, prev, curr) -> { - CompoundMark target = boat.getCurrentLeg().getEndCompoundMark(); - Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate()); - - nextMarkArrow.setX(view3D.getPivot().getX()); - nextMarkArrow.setY(view3D.getPivot().getY()); - nextMarkArrow.setZ(view3D.getPivot().getZ() + 10); - nextMarkArrow.setHeading(headingToMark.degrees()); - }; + this.pointToMark = new AnimationTimer() { + @Override + public void handle(long now) { + CompoundMark target = boat.getCurrentLeg().getEndCompoundMark(); + Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate()); - boat.positionProperty().addListener(pointToMark); + nextMarkArrow.setX(view3D.getPivot().getX()); + nextMarkArrow.setY(view3D.getPivot().getY()); + nextMarkArrow.setZ(view3D.getPivot().getZ() + 10); + nextMarkArrow.setHeading(headingToMark.degrees()); + } + }; + pointToMark.start(); } catch (BoatNotFoundException e) { e.printStackTrace(); } @@ -395,13 +427,7 @@ public class RaceViewController extends Controller { private void removeThirdPersonAnnotations(Subject3D subject3D) { viewSubjects.remove(nextMarkArrow); - - try { - VisualiserBoat boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID()); - boat.positionProperty().removeListener(pointToMark); - } catch (BoatNotFoundException e) { - e.printStackTrace(); - } + pointToMark.stop(); } /** diff --git a/racevisionGame/src/main/java/visualiser/layout/Shockwave.java b/racevisionGame/src/main/java/visualiser/layout/Shockwave.java new file mode 100644 index 00000000..efdb0c5d --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/layout/Shockwave.java @@ -0,0 +1,17 @@ +package visualiser.layout; + +import javafx.scene.paint.Color; +import javafx.scene.paint.PhongMaterial; +import javafx.scene.shape.Cylinder; +import javafx.scene.transform.Rotate; + +/** + * Created by cbt24 on 14/09/17. + */ +public class Shockwave extends Subject3D { + public Shockwave(double radius) { + super(new Cylinder(radius,0),0); + getMesh().getTransforms().add(new Rotate(-90, Rotate.X_AXIS)); + getMesh().setMaterial(new PhongMaterial(new Color(0,0,0,0))); + } +} diff --git a/racevisionGame/src/main/java/visualiser/layout/View3D.java b/racevisionGame/src/main/java/visualiser/layout/View3D.java index ddb06299..5709505c 100644 --- a/racevisionGame/src/main/java/visualiser/layout/View3D.java +++ b/racevisionGame/src/main/java/visualiser/layout/View3D.java @@ -1,5 +1,6 @@ package visualiser.layout; +import javafx.animation.AnimationTimer; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ChangeListener; @@ -71,21 +72,9 @@ public class View3D extends Pane { */ private Rotate pitch; /** - * Single listener for subject heading changes + * Animation loop for camera tracking */ - private ChangeListener pivotHeading = (o, prev, curr) -> yaw.setAngle((double)curr); - /** - * Single listener for subject position (x) changes - */ - private ChangeListener pivotX = (o, prev, curr) -> pivot.setX((double)curr); - /** - * Single listener for subject position (y) changes - */ - private ChangeListener pivotY = (o, prev, curr) -> pivot.setY((double)curr); - /** - * Single listener for subject position (z) changes - */ - private ChangeListener pivotZ = (o, prev, curr) -> pivot.setZ((double)curr); + private AnimationTimer trackBoat; /** * Distance to switch from third person to bird's eye */ @@ -219,10 +208,7 @@ public class View3D extends Pane { */ private void untrackSubject() { if(target.get() != null) { - target.get().getPosition().xProperty().removeListener(pivotX); - target.get().getPosition().yProperty().removeListener(pivotY); - target.get().getPosition().zProperty().removeListener(pivotZ); - target.get().getHeading().angleProperty().removeListener(pivotHeading); + trackBoat.stop(); target.setValue(null); } } @@ -234,13 +220,14 @@ public class View3D extends Pane { private void trackSubject(Subject3D subject) { target.set(subject); - updatePivot(target.get().getPosition()); - setYaw(target.get().getHeading().getAngle()); - - target.get().getPosition().xProperty().addListener(pivotX); - target.get().getPosition().yProperty().addListener(pivotY); - target.get().getPosition().zProperty().addListener(pivotZ); - target.get().getHeading().angleProperty().addListener(pivotHeading); + this.trackBoat = new AnimationTimer() { + @Override + public void handle(long now) { + updatePivot(target.get().getPosition()); + setYaw(target.get().getHeading().getAngle()); + } + }; + trackBoat.start(); } public void setNearClip(double nearClip) { diff --git a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java index 12e2ee37..1184197c 100644 --- a/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java +++ b/racevisionGame/src/main/java/visualiser/model/VisualiserBoat.java @@ -1,6 +1,8 @@ package visualiser.model; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.paint.Color; import network.Messages.Enums.BoatStatusEnum; @@ -62,6 +64,7 @@ public class VisualiserBoat extends Boat { private ObjectProperty positionProperty; private ObjectProperty bearingProperty; + private BooleanProperty hasCollided; /** @@ -74,6 +77,7 @@ public class VisualiserBoat extends Boat { super(boat.getSourceID(), boat.getName(), boat.getCountry()); this.color = color; + this.hasCollided = new SimpleBooleanProperty(false); } @@ -253,10 +257,6 @@ public class VisualiserBoat extends Boat { this.positionProperty.set(position); } - public ObjectProperty positionProperty() { - return positionProperty; - } - @Override public Bearing getBearing() { return bearingProperty.get(); @@ -270,7 +270,15 @@ public class VisualiserBoat extends Boat { this.bearingProperty.set(bearing); } - public ObjectProperty bearingProperty() { - return bearingProperty; + public boolean hasCollided() { + return hasCollided.get(); + } + + public BooleanProperty hasCollidedProperty() { + return hasCollided; + } + + public void setHasCollided(boolean hasCollided) { + this.hasCollided.set(hasCollided); } }