Merge branch 'story1299_next_mark_direction' into 'master'

Story1299 next mark direction

- Shows a 2d arrow to next mark when zoomed out
- Shows a 3d arrow to next mark when zoomed in

See merge request !63
main
Hamish Ball 8 years ago
commit f9f3213397

@ -40,7 +40,7 @@ public class LobbyController extends Controller {
private @FXML TextField addressFld;
private @FXML TextField portFld;
private ObservableList<RaceConnection> connections;
private ObservableList<RaceConnection> allConnections;
private ObservableList<RaceConnection> customConnections;
private AudioClip sound;
@ -51,12 +51,20 @@ public class LobbyController extends Controller {
public void initialize() {
httpMatchBrowserClient = new HttpMatchBrowserClient();
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshTable();
}
});
new Thread(httpMatchBrowserClient, "Match Client").start();
// set up the connection table
customConnections = FXCollections.observableArrayList();
allConnections = FXCollections.observableArrayList();
//connections.add(new RaceConnection("localhost", 4942, "Local Game"));
lobbyTable.setItems(httpMatchBrowserClient.connections);
lobbyTable.setItems(allConnections);
gameNameColumn.setCellValueFactory(cellData -> cellData.getValue().gamenameProperty());
hostNameColumn.setCellValueFactory(cellData -> cellData.getValue().hostnameProperty());
statusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());
@ -82,8 +90,14 @@ public class LobbyController extends Controller {
public void refreshBtnPressed(){
sound = new AudioClip(this.getClass().getResource("/visualiser/sounds/buttonpress.wav").toExternalForm());
sound.play();
refreshTable();
}
private void refreshTable() {
allConnections.clear();
addCustomGames();
addServerGames();
for(RaceConnection connection: connections) {
for(RaceConnection connection: allConnections) {
connection.check();
}
try {
@ -144,9 +158,9 @@ public class LobbyController extends Controller {
try {
int port = Integer.parseInt(portString);
customConnections.add(new RaceConnection(hostName, port, "Boat Game"));
connections.addAll(customConnections);
addressFld.clear();
portFld.clear();
refreshTable();
} catch (NumberFormatException e) {
System.err.println("Port number entered is not a number");
}
@ -173,17 +187,14 @@ public class LobbyController extends Controller {
* Adds the games received from the server
*/
private void addServerGames() {
httpMatchBrowserClient.connections.addAll(customConnections);
httpMatchBrowserClient.connections.addListener(new ListChangeListener<RaceConnection>() {
@Override
public void onChanged(Change<? extends RaceConnection> c) {
refreshBtnPressed();
}
});
allConnections.addAll(httpMatchBrowserClient.connections);
/*
for (HostGame game : matchBrowserLobbyInterface.getGames()) {
connections.add(new RaceConnection(game.getIp(), 4942, "Boat Game"));
}*/
}
private void addCustomGames() {
allConnections.addAll(customConnections);
}
}

@ -0,0 +1,123 @@
package visualiser.Controllers;
import com.interactivemesh.jfx.importer.stl.StlMeshImporter;
import javafx.animation.AnimationTimer;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
import javafx.scene.transform.Rotate;
import shared.model.Bearing;
import shared.model.CompoundMark;
import shared.model.GPSCoordinate;
import visualiser.layout.Annotation3D;
import visualiser.layout.Assets3D;
import visualiser.layout.Subject3D;
import visualiser.layout.View3D;
import visualiser.model.VisualiserBoat;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;
public class NextMarkController {
private @FXML StackPane arrowStackPane2d;
private @FXML StackPane arrowStackPane3d;
private @FXML Pane pane2d;
private @FXML Pane pane3d;
private VisualiserBoat boat;
public void initialiseArrowView(VisualiserBoat boat) {
this.boat = boat;
pane2d.setVisible(true);
pane3d.setVisible(false);
initialise2dArrowView();
initialise3dArrowView();
}
private void initialise2dArrowView() {
AnimationTimer arrow2d = new AnimationTimer() {
@Override
public void handle(long now) {
if (boat.getCurrentLeg().getEndCompoundMark() != null) {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
arrowStackPane2d.setRotate(headingToMark.degrees());
} else {
stop();
}
}
};
arrow2d.start();
}
private void initialise3dArrowView() {
ObservableList<Subject3D> viewSubjects = FXCollections.observableArrayList();
String arrowPath = "assets/mark_arrow.x3d";
Shape3D arrow = Assets3D.loadX3d(arrowPath);
arrow.setScaleX(25);
arrow.setScaleY(25);
arrow.setScaleZ(100);
arrow.setRotationAxis(new Point3D(1,0,0));
arrowStackPane3d.getChildren().add(arrow);
AnimationTimer arrow3d = new AnimationTimer() {
@Override
public void handle(long now) {
if (boat.getCurrentLeg().getEndCompoundMark() != null) {
arrow.getTransforms().clear();
double zRotation = calculateZRotate();
arrow.setRotate(calculateXRotate(zRotation));
arrow.getTransforms().add(new Rotate(zRotation, new Point3D(0, 0, 1)));
} else {
stop();
}
}
};
arrow3d.start();
}
public void show2d() {
pane3d.setVisible(false);
pane2d.setVisible(true);
}
public void show3d() {
pane2d.setVisible(false);
pane3d.setVisible(true);
}
private double calculateZRotate() {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
return -headingToMark.degrees() + boat.getBearing().degrees() + 180;
}
private double calculateXRotate(double zRotation) {
// if (zRotation > 360) {
// zRotation -=360;
// } else if (zRotation < 0) {
// zRotation += 360;
// }
//
// if (zRotation > 180) {
// zRotation = 360 - zRotation;
// }
return 70;
//return 90 - 20 * Math.cos(Math.toRadians(zRotation));
}
}

@ -19,10 +19,12 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.paint.Stop;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.Shape3D;
@ -82,10 +84,12 @@ public class RaceViewController extends Controller {
// note: it says it's not used but it is! do not remove :)
private @FXML ArrowController arrowController;
private @FXML NextMarkController nextMarkController;
private @FXML GridPane canvasBase;
private @FXML GridPane canvasBase1;
private @FXML SplitPane racePane;
private @FXML StackPane arrowPane;
private @FXML Pane nextMarkPane;
private @FXML Label timer;
private @FXML Label FPS;
private @FXML Label timeZone;
@ -288,19 +292,6 @@ public class RaceViewController extends Controller {
* Initialises the various UI components to listen to the {@link #visualiserRace}.
*/
private void initialiseRaceVisuals() {
// Import arrow mesh
URL asset = this.getClass().getClassLoader().getResource("assets/arrow V1.0.4.stl");
StlMeshImporter importer = new StlMeshImporter();
importer.read(asset);
MeshView arrow = new MeshView(importer.getImport());
PhongMaterial arrowMat = new PhongMaterial(Color.RED);
arrow.setMaterial(arrowMat);
this.nextMarkArrow = new Annotation3D(arrow);
this.nextMarkArrow.setScale(0.1);
// initialise displays
initialiseFps();
initialiseInfoTable();
@ -308,6 +299,7 @@ public class RaceViewController extends Controller {
initialiseRaceClock();
initialiseSpeedometer();
raceTimer(); // start the timer
nextMarkPane.toFront();
speedometerLoop();
new Sparkline(this.raceState, this.sparklineChart);
timeZone.setText(this.raceState.getRaceClock().getTimeZone());
@ -317,6 +309,12 @@ public class RaceViewController extends Controller {
private void initialiseView3D(VisualiserRaceEvent race) {
viewSubjects = FXCollections.observableArrayList();
try {
nextMarkController.initialiseArrowView(race.getVisualiserRaceState().getBoat(race.getVisualiserRaceState().getPlayerBoatID()));
} catch (BoatNotFoundException e) {
e.printStackTrace();
}
AmbientLight ambientLight = new AmbientLight(Color.web("#CCCCFF"));
ambientLight.setTranslateX(250);
ambientLight.setTranslateZ(210);
@ -387,11 +385,29 @@ public class RaceViewController extends Controller {
viewSubjects.add(markModel);
}
// Position and add each boat to view
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
Shape3D mesh = Assets3D.getBoat();
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
//mesh.setMaterial(boatColorMat);
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
// Configure visualiser for client's boat
if (boat.isClientBoat()) {
// Add player boat highlight
Shockwave boatHighlight = new Shockwave(10);
boatHighlight.getMesh().setMaterial(new PhongMaterial(new Color(1, 1, 0, 0.1)));
viewSubjects.add(boatHighlight);
// Track player boat with camera
viewSubjects.add(boatModel);
Platform.runLater(() -> {
view3D.trackSubject(boatModel);
view3D.setThirdPerson();
});
// Track player boat with highlight
AnimationTimer highlightTrack = new AnimationTimer() {
@Override
public void handle(long now) {
@ -400,28 +416,23 @@ public class RaceViewController extends Controller {
}
};
highlightTrack.start();
}
}
// Position and add each boat to view
for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) {
// MeshView mesh;
// if(boat.getSourceID() == race.getVisualiserRaceState().getPlayerBoatID()) {
// mesh = new MeshView(importer.getImport());
// } else {
// mesh = new MeshView(importerBurgerBoat.getImport());
// }
Shape3D mesh = Assets3D.getBoat();
PhongMaterial boatColorMat = new PhongMaterial(boat.getColor());
//mesh.setMaterial(boatColorMat);
Subject3D boatModel = new Subject3D(mesh, boat.getSourceID());
// Highlight next mark only for player boat
Material markColor = new PhongMaterial(new Color(0.15,0.9,0.2,1));
CompoundMark nextMark = boat.getCurrentLeg().getEndCompoundMark();
view3D.getShape(nextMark.getMark1().getSourceID()).getMesh().setMaterial(markColor);
if(nextMark.getMark2() != null) {
view3D.getShape(nextMark.getMark2().getSourceID()).getMesh().setMaterial(markColor);
}
boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
} else {
viewSubjects.add(boatModel);
}
//add sail
Sails3D sails3D = new Sails3D();
Subject3D sailsSubject = new Subject3D(sails3D, 0);
sails3D.setMouseTransparent(true);
sails3D.setMaterial(boatColorMat);
sailsSubject.setXRot(0d);
sailsSubject.setHeading(visualiserRace.getVisualiserRaceState().getWindDirection().degrees());
@ -502,17 +513,9 @@ public class RaceViewController extends Controller {
};
trackBoat.start();
Material markColor = new PhongMaterial(new Color(0.15,0.9,0.2,1));
CompoundMark nextMark = boat.getCurrentLeg().getEndCompoundMark();
view3D.getShape(nextMark.getMark1().getSourceID()).getMesh().setMaterial(markColor);
if(nextMark.getMark2() != null) {
view3D.getShape(nextMark.getMark2().getSourceID()).getMesh().setMaterial(markColor);
}
Subject3D shockwave = new Shockwave(10);
viewSubjects.add(shockwave);
boat.legProperty().addListener((o, prev, curr) -> Platform.runLater(() -> swapColours(curr)));
boat.hasCollidedProperty().addListener((o, prev, curr) -> Platform.runLater(() -> showCollision(boat, shockwave)));
}
// Fix initial bird's-eye position
@ -597,37 +600,32 @@ public class RaceViewController extends Controller {
}
private void addThirdPersonAnnotations(Subject3D subject3D) {
viewSubjects.add(nextMarkArrow);
final VisualiserBoat boat;
try {
boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
} catch (BoatNotFoundException e) {
e.printStackTrace();
return;
}
arrowToNextMark = new AnimationTimer() {
@Override
public void handle(long now) {
CompoundMark target = boat.getCurrentLeg().getEndCompoundMark();
if (target != null) {
Bearing headingToMark = GPSCoordinate.calculateBearing(boat.getPosition(), target.getAverageGPSCoordinate());
nextMarkArrow.setX(view3D.getPivot().getX());
nextMarkArrow.setY(view3D.getPivot().getY());
nextMarkArrow.setZ(view3D.getPivot().getZ() + 15);
nextMarkArrow.setHeading(headingToMark.degrees());
}
}
};
arrowToNextMark.start();
nextMarkController.show3d();
// viewSubjects.add(nextMarkArrow);
// final VisualiserBoat boat;
// try {
// boat = visualiserRace.getVisualiserRaceState().getBoat(subject3D.getSourceID());
// } catch (BoatNotFoundException e) {
// e.printStackTrace();
// return;
// }
// arrowToNextMark = new AnimationTimer() {
// @Override
// public void handle(long now) {
// 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() + 15);
// nextMarkArrow.setHeading(headingToMark.degrees());
// }
// };
// arrowToNextMark.start();
}
private void removeThirdPersonAnnotations() {
viewSubjects.remove(nextMarkArrow);
if (arrowToNextMark != null) {
arrowToNextMark.stop();
}
nextMarkController.show2d();
}
/**

@ -52,7 +52,7 @@ public class Assets3D {
windArrow = new Annotation3D(loadX3d(arrowPath));
}
private static Shape3D loadX3d(String path){
public static Shape3D loadX3d(String path){
X3dModelImporter x3dModelImporter = new X3dModelImporter();
URL asset = Assets3D.class.getClassLoader().getResource(path);
x3dModelImporter.read(asset);

@ -81,7 +81,7 @@ public class View3D extends Pane {
/**
* Distance to stop zoom
*/
private final double ZOOM_IN_LIMIT = 30;
private final double ZOOM_IN_LIMIT = 3;
private final double ZOOM_OUT_LIMIT = 700;
private final double MAX_ZOOM_LIMIT = 1500;
private final double MAX_PITCH = 60; // birds eye view

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D version="3.0" profile="Immersive" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="http://www.web3d.org/specifications/x3d-3.0.xsd">
<head>
<meta name="filename" content="Mark Arrow V1.3.x3d" />
<meta name="generator" content="Blender 2.77 (sub 0)" />
</head>
<Scene>
<NavigationInfo headlight="true"
visibilityLimit="0.0"
type='"EXAMINE", "ANY"'
avatarSize="0.25, 1.75, 0.75"
/>
<Background DEF="WO_World"
groundColor="0.051 0.051 0.051"
skyColor="0.051 0.051 0.051"
/>
<Transform DEF="Cube_TRANSFORM"
translation="0.000000 0.000000 0.000000"
scale="1.000000 1.000000 1.000000"
rotation="0.000000 0.707107 0.707107 3.141593"
>
<Transform DEF="Cube_ifs_TRANSFORM"
translation="0.000000 0.000000 0.000000"
scale="1.000000 1.000000 1.000000"
rotation="1.000000 0.000000 0.000000 0.000000"
>
<Group DEF="group_ME_Cube">
<Shape>
<Appearance>
<ImageTexture DEF="IM_Material_Diffuse_Color_002"
url='"textures/Material Diffuse Color.002" "Material Diffuse Color.002" "D:/Storage/3D Models/Misc/SENG302/Mark Arrow/textures/Material Diffuse Color.002"'
/>
<TextureTransform
translation="0.000000 0.000000"
scale="1.000000 1.000000"
rotation="0.000000"
/>
<Material DEF="MA_Material"
diffuseColor="0.800 0.800 0.800"
specularColor="0.401 0.401 0.401"
emissiveColor="0.000 0.000 0.000"
ambientIntensity="0.333"
shininess="0.098"
transparency="0.0"
/>
</Appearance>
<IndexedFaceSet solid="true"
texCoordIndex="0 1 2 -1 3 4 5 -1 6 7 8 9 -1 10 11 12 -1 13 14 15 -1 16 17 18 19 -1 20 21 22 -1 23 24 25 -1 26 27 28 29 -1 30 31 32 -1 33 34 35 -1 36 37 38 39 -1 "
coordIndex="4 1 7 -1 2 0 8 -1 1 0 2 3 -1 1 3 7 -1 8 0 9 -1 0 1 4 9 -1 4 7 6 -1 2 8 5 -1 6 3 2 5 -1 6 7 3 -1 8 9 5 -1 4 6 5 9 -1 "
>
<Coordinate DEF="coords_ME_Cube"
point="1.000000 -0.000000 -0.100000 1.000000 -0.000001 0.100000 0.000000 2.000000 -0.100000 0.000000 2.000000 0.100000 0.000000 -2.000000 0.100000 -1.000000 -0.000000 -0.100000 -1.000000 -0.000001 0.100000 0.000000 -0.000000 0.100000 0.000000 0.000000 -0.100000 0.000000 -2.000000 -0.100000 "
/>
<TextureCoordinate point="0.9999 0.0001 0.7826 0.0001 0.8260 0.0870 0.6522 0.1934 0.7826 0.3673 0.8260 0.2803 0.4348 0.1740 0.4348 0.1934 0.6522 0.1934 0.6522 0.1740 0.7826 0.0001 0.6522 0.1740 0.8260 0.0870 0.8260 0.2803 0.7826 0.3673 0.9999 0.3673 0.4348 0.1934 0.4348 0.1740 0.2174 0.1740 0.2174 0.1934 0.9999 0.0001 0.8260 0.0870 0.8695 0.1740 0.6522 0.1934 0.8260 0.2803 0.8695 0.1934 0.8695 0.1740 0.6522 0.1740 0.6522 0.1934 0.8695 0.1934 0.8695 0.1740 0.8260 0.0870 0.6522 0.1740 0.8260 0.2803 0.9999 0.3673 0.8695 0.1934 0.2174 0.1740 0.0001 0.1740 0.0001 0.1934 0.2174 0.1934 " />
</IndexedFaceSet>
</Shape>
</Group>
</Transform>
</Transform>
</Scene>
</X3D>

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

@ -41,6 +41,13 @@
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<StackPane fx:id="nextMarkPane" alignment="TOP_CENTER" mouseTransparent="true" prefHeight="150.0" prefWidth="150.0" snapToPixel="false">
<children>
<fx:include fx:id="nextMark" source="nextMark.fxml" />
</children>
</StackPane>
</children>
</GridPane>
<Pane prefHeight="200.0" prefWidth="400.0" visible="false">
<children>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<GridPane fx:id="arrowGridPane" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="visualiser.Controllers.NextMarkController">
<children>
<Pane fx:id="pane2d" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="112.0" prefWidth="112.0">
<children>
<StackPane fx:id="arrowStackPane2d" prefHeight="112.0" prefWidth="112.0">
<children>
<ImageView fx:id="arrowImage" fitHeight="75.0" fitWidth="25.0">
<image>
<Image url="@../../images/nextMarkArrow2d.png" />
</image>
</ImageView>
</children>
</StackPane>
</children>
</Pane>
<Pane fx:id="pane3d" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="112.0" prefWidth="112.0">
<children>
<StackPane fx:id="arrowStackPane3d" prefHeight="112.0" prefWidth="112.0" />
</children>
</Pane>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
Loading…
Cancel
Save