Compare commits

...

53 Commits

Author SHA1 Message Date
William Muir e5af7bf666 Minor fixes. Only one person can have wind walker now. Tokens spawn at 30s rather than 15
#story[1293]
2017-09-27 12:06:16 +13:00
William Muir 85ca91db96 Minor fixes. Only one person can have wind walker now. Tokens spawn at 30s rather than 15
#story[1293]
2017-09-27 11:55:40 +13:00
William Muir 2eb7e603f1 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps 2017-09-27 03:01:41 +13:00
William Muir 658a342118 Added the bad random to git sorree forgot to git add
#story[1293]
2017-09-27 03:01:23 +13:00
Calum Irwin ea52977aeb Merge branch '1293_PowerUps' into 'develop'
1293 power ups

# Changes 
* Token Objects added to represent pickups along with their corresponding mesh objects 
* Yachts now have a powerup attribute 
* Power up attribute is checked in Game State updates and updates are now done appropriately, dependant on this power up 
* RaceViewController now has a grid pane to show the different power up icons. These will display when a token is picked up and blink when they are about to dissapear
* Token generator created. This generates token locations randomly in the map in circles centred between the legs of the race 
* Added Yacht EventCodes for the different type of power / up / down status effect actions
 
# Refactor
* Moved Timer tasks such as spawn tokens and update wind into the GameState where they belong
* Moved the creation of some messages in odd places, server side, into the MessageFactory class 
 
# Testing 
* Manual test done
* Junits created for the random token generator

See merge request !77
2017-09-27 02:47:57 +13:00
William Muir 10fa51a105 Added some testing for the Random spawner
#story[1293]
2017-09-27 02:27:30 +13:00
William Muir c54a1e141d Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/resources/views/RaceView.fxml
2017-09-27 01:49:18 +13:00
William Muir 6d51ea3574 Created a random place token generator.
Generates a location between any leg of the race in a random angle / distance of the radius of the centre point of the two gates to one of the gates

#story[1293]
2017-09-27 01:44:01 +13:00
Zhi You Tan d56468e4aa - Fixed snackbar not showing on race view
- Added close label on server creation dialog

#story[1273]
2017-09-27 00:38:42 +13:00
Zhi You Tan 5248921576 Multiple fixes:
- fix last button no longer default focused when loading keybinding dialog
- fix click and mouse exit still focused on button
- closing keybinding does not focus on chat anymore

#story[1273]
2017-09-26 22:52:58 +13:00
William Muir 330ccd272d The random token now has a 50% chance of causing your boat to have a speed penalty
#story[1293]
2017-09-26 21:13:35 +13:00
William Muir 4b7dfe38c4 Fixed Boats powering up and down correctly. Icons respond correctly
#story[1293]
2017-09-26 19:43:32 +13:00
William Muir ab07c7f298 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-26 19:01:53 +13:00
William Muir b5076bc976 Fixed wind walker and bumper
Added a hack to bumper so that the collision distance is larger than the regular collision distance
Wind walker now makes you go at you max speed rather than VMG speed

#story[1293]
2017-09-26 18:57:15 +13:00
Michael Rausch 2dcdd1c248 Merge branch '1273_Changing_Cameras' into 'develop'
1273 changing cameras

# Multiple Camera Views

## 3 Camera Views Implemented
1. Normal 3D (Isometric)
2. Top Down Perspective
3. Chase Cam (Over the Shoulder)

- Isometric and Top Down Perspectives can Pan within limits.
- Chase Cam rotates the camera around the boat. (While still following it)
- All camera views can Zoom.

# Testing

No testing completed other than manually testing myself. A proper manual test should be completed by the merger.

See merge request !76
2017-09-26 18:36:59 +13:00
Alistair McIntyre 9b00f76907 removed print statements and added documentation.
tags : #story[1273]
2017-09-26 18:36:13 +13:00
Alistair McIntyre f11c457d28 removed print statements
tags : #story[1273]
2017-09-26 18:31:47 +13:00
Michael Rausch 9e4fa30787 Merge branch 'issue68_boat_not_turning_on_starbord_vmg' into 'develop'
the boat can now turn after snapping to starboard vmg #story[1273]



See merge request !75
2017-09-26 18:11:24 +13:00
Alistair McIntyre 99ce4fa11d Merged develop in and reimplemented keybindings for moving the camera.
tags : #story[1273]
2017-09-26 18:01:39 +13:00
Alistair McIntyre 69d1fa9488 Merge branch 'develop' into 1273_Changing_Cameras 2017-09-26 17:36:40 +13:00
Alistair McIntyre 66e6a8a2a4 - Small Changes
tags : #story[1273]
2017-09-26 17:35:36 +13:00
William Muir 8ba44d7476 Minor commit for testing
#story[1293]
2017-09-26 17:19:45 +13:00
Peter Galloway dd43097677 the boat can now turn after snapping to starboard vmg #story[1273] 2017-09-26 17:07:55 +13:00
Alistair McIntyre 1a53579317 - Isometric Camera
- Zoom Bounds added.
 - Camera Panning Bounds added. Need to be tested with extra maps.

tags : #story[1273]
2017-09-26 16:57:07 +13:00
Haoming Yin 132a729758 Temporarily added more options in key binding dialog. But still need to implement binding after camera story has been merged into develop
tags: #story[1273]
2017-09-26 15:49:16 +13:00
alistairjmcintyre 2e7487fdfc - Chase Camera:
- Has panning bounds, zoom bounds, and general tidy up.
 - Now correctly observes the boat object rather than getting information from both the boat object AND the client yacht model.

Top Down Camera:
 - Can only pan within certain bounds now, and will continue to follow the boat regardless.
 - Can only zoom within certain bounds now.

Isometric Camera:
 - Nothing changed.

#tags [1273]
2017-09-26 15:06:21 +13:00
Haoming Yin 1bd4db73cd Issue 66: client side error pop ups use default javaFx style
- created JFeonix style pop up to replace the default one

tags: #story[1273]
2017-09-26 14:44:37 +13:00
William Muir 7a4cdbe0c9 Fixed WindWalker
#story[1293]
2017-09-26 11:12:29 +13:00
Calum 7027de80c4 Fixed issues with correct protocol implementation.
#issue[64] #fix #testmanual
2017-09-25 22:09:26 +13:00
William Muir 0211f2df38 Merged dev back on
#story[1293]
2017-09-25 17:38:09 +13:00
William Muir dba5a5680f Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/resources/views/RaceView.fxml
2017-09-25 17:20:25 +13:00
William Muir 5c50e77efa Merge branch 'Story1278_keybindings' into 'develop'
Story1278 keybindings

# Changes

- Added customised action key binding for all boat actions
- Users can select the turning mode (continuously turning mode, and the default turning mode)
- Refined UI design for key bindings
- Added animation which mouse enters/exits the setting button, and also prompt text to guide users to press key
- Popup window to inform users if their key assignment is successful or not

# Testing

## Manual testing log as below (all passed according to the assigner)
- if a player toggles the turning mode toggle button, the labels for upwind and downwind will be changed correspondingly
- if a player clicks the "reset" button, all the key binding settings will be reset to default
- if a player assigns a key which is already is in use, a popup box will inform the assignment is failed, and action will be changed back
- if a player assigns a key successfully, a popup will inform the success, and the new key binding will appear on the button
- A player can change their key bindings before the race starts and during the race


See merge request !73
2017-09-25 17:11:12 +13:00
Alistair McIntyre 00b09997b0 - Added Camera panning to chase camera mode.
tags : #story[1273]
2017-09-25 16:28:37 +13:00
Alistair McIntyre d250c635d8 - Adjusted server tick rate to test smoothing
tags : #story[1273]
2017-09-25 15:32:13 +13:00
Alistair McIntyre 376c4d25a8 Merge branch 'develop' into 1273_Changing_Cameras
# Conflicts:
#	src/main/java/seng302/model/ClientYacht.java
2017-09-25 14:40:19 +13:00
Alistair McIntyre e66abb4340 - An attempt at chase cam smoothing. needs work.
tags : #story[1273]
2017-09-25 14:39:09 +13:00
Alistair McIntyre a19e191684 - Chase cam kind of working, need to find a fix for the abrupt direction change.
tags : #story[1273]
2017-09-25 14:03:47 +13:00
William Muir 29b97a194d Merged dev back on
#story[1293]
2017-09-25 11:26:44 +13:00
William Muir 8a0ad8d6a9 Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/model/ServerYacht.java
2017-09-25 11:19:10 +13:00
William Muir 78259f8e33 Boat now changes color when it is bumped for a time
ClientYacht: Added ColorChangeListener from GameView3D to re paint the boat when the color attribute is changed

#story[1293]
2017-09-23 16:54:03 +12:00
William Muir c47e5b1450 Boat now changes color when it is bumped for a time
ClientYacht: Added ColorChangeListener from GameView3D to re paint the boat when the color attribute is changed

#story[1293]
2017-09-23 16:31:18 +12:00
William Muir 8c7f9a878d Created Boat bumper logic. Refactored logic for powering up / dpwn
YachtEventType: Added some new events, a generic power down event and a bumper_crash event for an affected boat
GameState: Implemented boat bumper logic
MessageFactory: Made new messages for powerdown and status effect
ClientYacht: Had to create another powerDown functional interface to inform the race view controller when to turn off the icon
RaceViewController/GameClient: Now waits for a message about powering down before turning off rather than waiting time client side

#story[1293]
2017-09-23 13:23:16 +12:00
William Muir ecb3d4ecbf Removed sendServerMessage to be replaced with notifyMessageListeners. Minor structure move arounds
#story[1293]
2017-09-23 11:49:56 +12:00
William Muir e61b6d50a1 Small refactor. Fixed tokens to spawn on the minute mark.
Moved updates of wind and token timers into gamestate from mainserver thread. Now triggered upon GameState change to start

#story[1293]
2017-09-23 11:33:01 +12:00
William Muir 061e49bab9 Implemented wind walker algorithm. Refactored some GameState updating logic to allow for better token logic integration
GameState: Moved all token logic into its own function startPoint so that it is dsijoint from other updating logic
GameState: Implemented wind walker algorithm.
GameState: Changed Generic 'speedMultiplier' to 'serverSpeedMultiplier' to make it obviously disjoint from a boats speed multiplier
MessageFactory: Moved some found message creation (Chatter Message)  server side into MessageFactory that wasnt already there
ServerYacht: Added a speed multiplier and a handling multiplier to the serveryacht class that is set and reset upon powerup / down

#story[1293]
2017-09-22 23:44:03 +12:00
William Muir a3c555d5fe Merge remote-tracking branch 'origin/develop' into 1293_PowerUps
# Conflicts:
#	src/main/java/seng302/model/ClientYacht.java
2017-09-22 21:18:58 +12:00
Alistair McIntyre 6ff309a40c - Perspective Camera Works
- Top Down Camera Works
- Started on chase cam but the math is a bit tricky.

tags : #story[1273]
2017-09-21 14:40:35 +12:00
William Muir 3be8cd264d Adding icon files to git
#story[1245]
2017-09-20 17:52:02 +12:00
William Muir 66d9a06f9e Adding icon files to git
#story[1245]
2017-09-20 17:19:14 +12:00
William Muir 034e4c252a Icons now display, blink when they are about to run off, and turn off after their time out
TokenType Enum now also has a timeout construction field
#story[1245]
2017-09-20 13:09:09 +12:00
William Muir 6cde016401 Fixed random token assigning and realisation
Token class now has two functions: assignRandomType and realiseRandomType
The former can be used to assign any random type to the token including the random type
The latter can be used to assign a concrete random type to the token (not the random type)

#story[1245]
2017-09-20 12:02:12 +12:00
William Muir 52d3cea592 Added preliminary icons for pickups
RaceView now has a grid pane to contain some icons to display power ups. These are just preliminary

ClientYacht now has a power up field that is set from recieveing messages in the Game Client, as well as observed by the RaceViewController to display the relevant icon when the powerup field is changed

#story[1245]
2017-09-19 23:04:17 +12:00
William Muir 78596ea111 Initial commit for Power Up story
Made new preliminary models for each power up. Currently just different colour balls
Added new YachtEventTypes in the enum for each pick up to be sent out to clients
Tokens now not only randomise location but also randomise which type of token will be sent out
Added new methods to the MessageFactory class - Make collision and Make pickup Message
Game Client now checks what type of Yacht Event code has come in to respond appropriately rather than just generic collision / token.. although this has not been implemented yet
Game View loads appropriate token models depending on what is in XML

#story[1245]
2017-09-19 17:47:05 +12:00
54 changed files with 2795 additions and 517 deletions
+276 -113
View File
@@ -4,10 +4,13 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@@ -36,6 +39,7 @@ import seng302.model.mark.MarkOrder;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.RandomSpawn;
import seng302.utilities.XMLParser; import seng302.utilities.XMLParser;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
@@ -54,24 +58,38 @@ public class GameState implements Runnable {
private static Logger logger = LoggerFactory.getLogger(GameState.class); private static Logger logger = LoggerFactory.getLogger(GameState.class);
private static final Integer STATE_UPDATES_PER_SECOND = 60;
//Scheduling constants
static final int WARNING_TIME = 10 * -1000; static final int WARNING_TIME = 10 * -1000;
static final int PREPATORY_TIME = 5 * -1000; static final int PREPATORY_TIME = 5 * -1000;
private static final int TIME_TILL_START = 10 * 1000; private static final int TIME_TILL_START = 10 * 1000;
private static final Long POWERUP_TIMEOUT_MS = 10_000L; //Wind Constants
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
private static final Integer STATE_UPDATES_PER_SECOND = 60; //Rounding Constants
private static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further private static final Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
//Collision constants
private static final Double MARK_COLLISION_DISTANCE = 15d; private static final Double MARK_COLLISION_DISTANCE = 15d;
public static final Double YACHT_COLLISION_DISTANCE = 25.0; public static final Double YACHT_COLLISION_DISTANCE = 25.0;
private static final Double BOUNCE_DISTANCE_MARK = 20.0; private static final Double BOUNCE_DISTANCE_MARK = 20.0;
public static final Double BOUNCE_DISTANCE_YACHT = 30.0; public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
private static final Double COLLISION_VELOCITY_PENALTY = 0.3; private static final Double COLLISION_VELOCITY_PENALTY = 0.3;
//Powerup Constants
public static final Double VELOCITY_BOOST_MULTIPLIER = 2d;
public static final Integer HANDLING_BOOST_MULTIPLIER = 2;
private static final Double BAD_RANDOM_SPEED_PENALTY = 0.3;
public static final Long BUMPER_DISABLE_TIME = 5_000L;
private static final Long TOKEN_SPAWN_TIME = 30_000L;
private static Long previousUpdateTime; private static Long previousUpdateTime;
public static Double windDirection; public static Double windDirection;
private static Double windSpeed; private static Double windSpeed;
private static Double speedMultiplier = 1d; private static Double serverSpeedMultiplier;
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat. private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
private static Boolean playerHasLeftFlag; private static Boolean playerHasLeftFlag;
@@ -83,13 +101,12 @@ public class GameState implements Runnable {
private static GameStages currentStage; private static GameStages currentStage;
private static MarkOrder markOrder; private static MarkOrder markOrder;
private static long startTime; private static long startTime;
private static Set<Mark> marks; private static List<Mark> marks;
private static List<Limit> courseLimit; private static List<Limit> courseLimit;
private static Integer maxPlayers = 8; private static Integer maxPlayers = 8;
private static List<Token> allTokens;
private static List<Token> tokensInPlay; private static List<Token> tokensInPlay;
private static RandomSpawn randomSpawn;
private static List<NewMessageListener> newMessageListeners; private static List<NewMessageListener> newMessageListeners;
@@ -100,26 +117,22 @@ public class GameState implements Runnable {
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>(); yachts = new HashMap<>();
tokensInPlay = new ArrayList<>(); tokensInPlay = new ArrayList<>();
players = new ArrayList<>(); players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress; GameState.hostIpAddress = hostIpAddress;
customizationFlag = false; customizationFlag = false;
playerHasLeftFlag = false; playerHasLeftFlag = false;
speedMultiplier = 1.0; serverSpeedMultiplier = 1.0;
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
//set this when game stage changes to prerace
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map? markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
newMessageListeners = new ArrayList<>(); newMessageListeners = new ArrayList<>();
allTokens = makeTokens(); marks = new MarkOrder().getAllMarks();
randomSpawn = new RandomSpawn(markOrder.getOrderedUniqueCompoundMarks());
resetStartTime(); resetStartTime();
new Thread(this, "GameState").start(); //Run the auto updates on the game state
marks = new MarkOrder().getAllMarks();
setCourseLimit("/server_config/race.xml"); setCourseLimit("/server_config/race.xml");
new Thread(this, "GameState").start(); //Run the auto updates on the game state
} }
private void setCourseLimit(String url) { private void setCourseLimit(String url) {
@@ -137,29 +150,10 @@ public class GameState implements Runnable {
courseLimit = XMLParser.parseRace(document).getCourseLimit(); courseLimit = XMLParser.parseRace(document).getCourseLimit();
} }
/**
* Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
* race ideally
*
* @return A list of possible tokensInPlay for this race
*/
private ArrayList<Token> makeTokens() {
Token token1 = new Token(TokenType.BOOST, 57.66946, 11.83154);
Token token2 = new Token(TokenType.BOOST, 57.66877, 11.83382);
Token token3 = new Token(TokenType.BOOST, 57.66914, 11.83965);
Token token4 = new Token(TokenType.BOOST, 57.66684, 11.83214);
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
}
public static String getHostIpAddress() { public static String getHostIpAddress() {
return hostIpAddress; return hostIpAddress;
} }
public static Set<Mark> getMarks() {
return Collections.unmodifiableSet(marks);
}
public static List<Player> getPlayers() { public static List<Player> getPlayers() {
return players; return players;
} }
@@ -260,16 +254,75 @@ public class GameState implements Runnable {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("[GameState] interrupted exception"); System.out.println("[GameState] interrupted exception");
} }
if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) { if (currentStage == GameStages.PRE_RACE) {
update(); update();
if (System.currentTimeMillis() > startTime) {
startSpawningTokens();
startUpdatingWind();
GameState.setCurrentStage(GameStages.RACING);
}
} }
if (currentStage == GameStages.RACING) { if (currentStage == GameStages.RACING) {
update(); update();
} }
} }
} }
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer("Token Spawning Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
spawnNewToken();
notifyMessageListeners(MessageFactory.getRaceXML());
}
}, 0, TOKEN_SPAWN_TIME);
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind() {
Timer timer = new Timer("Wind Updating Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
private static void updateWind() {
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0) {
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
} else {
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED) {
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED) {
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
public static void updateBoat(Integer sourceId, BoatAction actionType) { public static void updateBoat(Integer sourceId, BoatAction actionType) {
ServerYacht playerYacht = yachts.get(sourceId); ServerYacht playerYacht = yachts.get(sourceId);
switch (actionType) { switch (actionType) {
@@ -304,10 +357,12 @@ public class GameState implements Runnable {
* Randomly select a subset of tokensInPlay from a pre defined superset * Randomly select a subset of tokensInPlay from a pre defined superset
* Broadasts a new race status message to show this update * Broadasts a new race status message to show this update
*/ */
public static void spawnNewToken() { private void spawnNewToken() {
Random random = new Random();
tokensInPlay.clear(); tokensInPlay.clear();
tokensInPlay.add(allTokens.get(random.nextInt(allTokens.size()))); Token token = randomSpawn.getRandomTokenLocation();
// token.assignType(TokenType.WIND_WALKER);
logger.debug("Spawned token of type " + token.getTokenType());
tokensInPlay.add(token);
} }
/** /**
@@ -324,14 +379,12 @@ public class GameState implements Runnable {
Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0; Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0;
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
if (System.currentTimeMillis() > startTime) {
GameState.setCurrentStage(GameStages.RACING);
}
for (ServerYacht yacht : yachts.values()) { for (ServerYacht yacht : yachts.values()) {
updateVelocity(yacht); updateVelocity(yacht);
checkPowerUpTimeout(yacht);
yacht.runAutoPilot(); yacht.runAutoPilot();
yacht.updateLocation(timeInterval); yacht.updateLocation(timeInterval);
preformTokenUpdates(yacht); //This update must be done before collision. Sorta hacky
checkCollision(yacht); checkCollision(yacht);
if (yacht.getBoatStatus() != BoatStatus.FINISHED) { if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
checkForLegProgression(yacht); checkForLegProgression(yacht);
@@ -345,17 +398,136 @@ public class GameState implements Runnable {
} }
private void checkPowerUpTimeout(ServerYacht yacht) { /**
if (yacht.getPowerUp() != null) { * All token functionality entry points is taken care of here. So can be disabled and enabled
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) { * easily
yacht.powerDown(); *
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired"); * @param yacht The yacht to perform token checks on
logger.debug("Yacht: " + yacht.getShortName() + " powered down!"); */
private void preformTokenUpdates(ServerYacht yacht) {
Token collidedToken = checkTokenPickUp(yacht);
if (collidedToken != null) {
tokensInPlay.remove(collidedToken);
powerUpYacht(yacht, collidedToken);
}
checkPowerUpTimeout(yacht);
TokenType powerUp = yacht.getPowerUp();
if (powerUp != null) {
switch (powerUp) {
case WIND_WALKER:
windWalk(yacht);
break;
case BUMPER:
ServerYacht collidedYacht = checkYachtCollision(yacht, true);
if (collidedYacht != null) {
yacht.powerDown();
boatTempShutDown(collidedYacht);
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
notifyMessageListeners(
MessageFactory.makeStatusEffectMessage(collidedYacht, powerUp));
}
break;
case RANDOM:
yacht.setPowerUpSpeedMultiplier(BAD_RANDOM_SPEED_PENALTY);
} }
} }
} }
/**
* Powers up a thisYacht with the given token type.
*
* @param thisYacht The yacht to be powered up
* @param collidedToken The token which this thisYacht collided with
*/
private void powerUpYacht(ServerYacht thisYacht, Token collidedToken) {
//The random token has a 50% chance of becoming another token else becoming a speed detriment!
if (collidedToken.getTokenType() == TokenType.RANDOM && new Random().nextBoolean()) {
collidedToken.realiseRandom();
}
//If another yacht has the wind walker token, They should be powered down. Only one allowed!
else if (collidedToken.getTokenType() == TokenType.WIND_WALKER) {
for (ServerYacht otherYacht : yachts.values()) {
if (otherYacht != thisYacht && otherYacht.getPowerUp() == TokenType.WIND_WALKER) {
powerDownYacht(otherYacht);
}
}
}
thisYacht.powerUp(collidedToken.getTokenType());
String logMessage =
thisYacht.getBoatName() + " has picked up a " + collidedToken.getTokenType().getName()
+ " token";
notifyMessageListeners(
MessageFactory.makeChatterMessage(thisYacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(MessageFactory.makePickupMessage(thisYacht, collidedToken));
logger.debug(
"Yacht: " + thisYacht.getShortName() + " got powerup " + collidedToken.getTokenType());
}
private void powerDownYacht(ServerYacht yacht) {
String logMessage =
yacht.getBoatName() + "'s " + yacht.getPowerUp().getName() + " expired";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
yacht.powerDown();
}
// TODO: 23/09/17 wmu16 - This is a hacky way to have the boat power down. Need some sort of separation between token and status effect :/
/**
* Disables the given boat for BUMPER_DISABLE_TIME ms.
*
* @param yacht The yacht to disable
*/
private void boatTempShutDown(ServerYacht yacht) {
yacht.setPowerUpSpeedMultiplier(0d);
Timer shutDownTimer = new Timer("Shutdown Timer");
shutDownTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.powerDown(); //Note this actually resets the boat to normal.
}
}, BUMPER_DISABLE_TIME);
}
/**
* Checks how long a powerup has been active for. If it has exceeded its timeout, it powers the
* yacht down.
*
* @param yacht The yacht to check to power down
*/
private void checkPowerUpTimeout(ServerYacht yacht) {
if (yacht.getPowerUp() != null) {
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > yacht.getPowerUp()
.getTimeout()) {
powerDownYacht(yacht);
}
}
}
/**
* This function changes the wind to be at an angle that causes the yacht in question to be at
* its fastest velocity
*
* @param yacht The yacht to fix the wind for
*/
private void windWalk(ServerYacht yacht) {
Double optimalAngle = PolarTable.getOptimalAngle();
Double heading = yacht.getHeading();
windDirection = (double) Math.floorMod(Math.round(heading + optimalAngle), 360L);
}
/** /**
* Check if the yacht has crossed the course limit * Check if the yacht has crossed the course limit
* *
@@ -377,13 +549,15 @@ public class GameState implements Runnable {
} }
/** /**
* Checks all tokensInPlay to see if a yacht has picked one up * Checks all tokensInPlay to see if a yacht has picked one up. If so, the yacht is powered up
* @return Token which was collided with * in the appropriate way
* @param serverYacht The yacht to check for collision with a token * @param yacht The yacht to check for collision with a token
*
* @return The token collided with
*/ */
private static Token checkTokenPickUp(ServerYacht serverYacht) { private Token checkTokenPickUp(ServerYacht yacht) {
for (Token token : tokensInPlay) { for (Token token : tokensInPlay) {
Double distance = GeoUtility.getDistance(token, serverYacht.getLocation()); Double distance = GeoUtility.getDistance(token, yacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) { if (distance < YACHT_COLLISION_DISTANCE) {
return token; return token;
} }
@@ -406,7 +580,7 @@ public class GameState implements Runnable {
*/ */
public static void checkCollision(ServerYacht serverYacht) { public static void checkCollision(ServerYacht serverYacht) {
//Yacht Collision //Yacht Collision
ServerYacht collidedYacht = checkYachtCollision(serverYacht); ServerYacht collidedYacht = checkYachtCollision(serverYacht, false);
Mark collidedMark = checkMarkCollision(serverYacht); Mark collidedMark = checkMarkCollision(serverYacht);
if (collidedYacht != null) { if (collidedYacht != null) {
@@ -423,9 +597,7 @@ public class GameState implements Runnable {
collidedYacht.setCurrentVelocity( collidedYacht.setCurrentVelocity(
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners( notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
} }
//Mark Collision //Mark Collision
@@ -437,9 +609,7 @@ public class GameState implements Runnable {
serverYacht.setCurrentVelocity( serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners( notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
} }
//Boundary Collision //Boundary Collision
@@ -452,22 +622,7 @@ public class GameState implements Runnable {
serverYacht.setCurrentVelocity( serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners( notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht));
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
}
//Token Collision
Token collidedToken = checkTokenPickUp(serverYacht);
if (collidedToken != null) {
sendServerMessage(serverYacht.getSourceId(), serverYacht.getBoatName() + " has picked speed-up token");
tokensInPlay.remove(collidedToken);
serverYacht.powerUp(collidedToken.getTokenType());
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
.getTokenType());
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
} }
} }
@@ -475,29 +630,30 @@ public class GameState implements Runnable {
private void updateVelocity(ServerYacht yacht) { private void updateVelocity(ServerYacht yacht) {
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier(); Double maxBoatSpeed =
if (yacht.getPowerUp() != null) { GeoUtility.knotsToMMS(boatSpeedInKnots) * serverSpeedMultiplier * yacht
if (yacht.getPowerUp().equals(TokenType.BOOST)) { .getPowerUpSpeedMultiplier() * yacht.getBoatTypeSpeedMultiplier();
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
maxBoatSpeed *= 2;
}
}
Double currentVelocity = yacht.getCurrentVelocity(); Double currentVelocity = yacht.getCurrentVelocity();
// TODO: 15/08/17 remove magic numbers from these equations. // TODO: 15/08/17 remove magic numbers from these equations.
if (yacht.getSailIn()) { if (yacht.getSailIn()) {
if (currentVelocity < maxBoatSpeed - 500) { if (currentVelocity < maxBoatSpeed - 500) {
yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier()); yacht.changeVelocity(
(maxBoatSpeed / 100) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > maxBoatSpeed + 500) { } else if (currentVelocity > maxBoatSpeed + 500) {
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); yacht.changeVelocity(
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else { } else {
yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier()); yacht
.setCurrentVelocity((maxBoatSpeed) * yacht.getBoatTypeAccelerationMultiplier());
} }
} else { } else {
if (currentVelocity > 3000) { if (currentVelocity > 3000) {
yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier()); yacht.changeVelocity(
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > 100) { } else if (currentVelocity > 100) {
yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier()); yacht.changeVelocity(
(-currentVelocity / 50) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity <= 100) { } else if (currentVelocity <= 100) {
yacht.setCurrentVelocity(0d); yacht.setCurrentVelocity(0d);
} }
@@ -560,7 +716,10 @@ public class GameState implements Runnable {
if (hasProgressed) { if (hasProgressed) {
if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) { if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) {
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed leg " + yacht.getLegNumber());
String logMessage = yacht.getBoatName() + " passed leg " + yacht.getLegNumber();
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
} }
yacht.incrementLegNumber(); yacht.incrementLegNumber();
sendMarkRoundingMessage(yacht); sendMarkRoundingMessage(yacht);
@@ -596,7 +755,9 @@ public class GameState implements Runnable {
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) { if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.RACING); yacht.setBoatStatus(BoatStatus.RACING);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line"); String logMessage = yacht.getBoatName() + " passed start line";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -700,7 +861,10 @@ public class GameState implements Runnable {
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) { if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.FINISHED); yacht.setBoatStatus(BoatStatus.FINISHED);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed finish line");
String logMessage = yacht.getBoatName() + " passed finish line";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -723,6 +887,7 @@ public class GameState implements Runnable {
String name = new String(customizeData); String name = new String(customizeData);
playerYacht.setBoatName(name); playerYacht.setBoatName(name);
} else if (requestType.equals(CustomizeRequestType.COLOR)) { } else if (requestType.equals(CustomizeRequestType.COLOR)) {
//This low level stuff shouldnt be here alistair! In fact no logic LIKE THIS should! - wmu16
int red = customizeData[0] & 0xFF; int red = customizeData[0] & 0xFF;
int green = customizeData[1] & 0xFF; int green = customizeData[1] & 0xFF;
int blue = customizeData[2] & 0xFF; int blue = customizeData[2] & 0xFF;
@@ -735,7 +900,7 @@ public class GameState implements Runnable {
} }
private static Mark checkMarkCollision(ServerYacht yacht) { private static Mark checkMarkCollision(ServerYacht yacht) {
Set<Mark> marksInRace = GameState.getMarks(); Set<Mark> marksInRace = new HashSet<>(marks);
for (Mark mark : marksInRace) { for (Mark mark : marksInRace) {
if (GeoUtility.getDistance(yacht.getLocation(), mark) if (GeoUtility.getDistance(yacht.getLocation(), mark)
<= MARK_COLLISION_DISTANCE) { <= MARK_COLLISION_DISTANCE) {
@@ -764,15 +929,22 @@ public class GameState implements Runnable {
* Collision detection which iterates through all the yachts and check if any yacht collided * Collision detection which iterates through all the yachts and check if any yacht collided
* with this yacht. Return collided yacht or null if no collision. * with this yacht. Return collided yacht or null if no collision.
* *
* UPDATE: HACK!!! wmu16 - forBumperCollision is (the goddamn dirtiest) dirty flag to fix a
* weird bug where the bumper collision would not be registerd but the knock back collision would.
* In other words, only set the 'forBumperCollision' flag true if used for the bumper power up.
*
* @return yacht to compare to all other yachts. * @return yacht to compare to all other yachts.
*/ */
private static ServerYacht checkYachtCollision(ServerYacht yacht) { private static ServerYacht checkYachtCollision(ServerYacht yacht, Boolean forBumperCollision) {
Double collisionDistance =
(forBumperCollision) ? YACHT_COLLISION_DISTANCE + 2.5 : YACHT_COLLISION_DISTANCE;
for (ServerYacht otherYacht : GameState.getYachts().values()) { for (ServerYacht otherYacht : GameState.getYachts().values()) {
if (otherYacht != yacht) { if (otherYacht != yacht) {
Double distance = GeoUtility Double distance = GeoUtility
.getDistance(otherYacht.getLocation(), yacht.getLocation()); .getDistance(otherYacht.getLocation(), yacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) { ;
if (distance < collisionDistance) {
return otherYacht; return otherYacht;
} }
} }
@@ -808,13 +980,6 @@ public class GameState implements Runnable {
roundingMark.getSourceID())); roundingMark.getSourceID()));
} }
public static void sendServerMessage(Integer messageType, String message) {
notifyMessageListeners(new ChatterMessage(
messageType, "SERVER: " + message
));
}
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) { public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
String chatterText = chatterMessage.getMessage(); String chatterText = chatterMessage.getMessage();
String[] words = chatterText.split("\\s+"); String[] words = chatterText.split("\\s+");
@@ -822,17 +987,19 @@ public class GameState implements Runnable {
switch (words[2].trim()) { switch (words[2].trim()) {
case "/speed": case "/speed":
try { try {
setSpeedMultiplier(Double.valueOf(words[3])); serverSpeedMultiplier = Double.valueOf(words[3]);
sendServerMessage(chatterMessage.getMessage_type(), String logMessage = "Speed modifier set to x" + words[3];
"Speed modifier set to x" + words[3]); notifyMessageListeners(MessageFactory
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
} catch (Exception e) { } catch (Exception e) {
Logger logger = LoggerFactory.getLogger(GameState.class); Logger logger = LoggerFactory.getLogger(GameState.class);
logger.error("cannot parse >speed value"); logger.error("cannot parse >speed value");
} }
return; return;
case "/finish": case "/finish":
sendServerMessage(chatterMessage.getMessage_type(), String logMessage = "Game will now finish";
"Game will now finish"); notifyMessageListeners(MessageFactory
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
endRace(); endRace();
return; return;
} }
@@ -889,11 +1056,7 @@ public class GameState implements Runnable {
currentStage = GameStages.FINISHED; currentStage = GameStages.FINISHED;
} }
public static void setSpeedMultiplier (double multiplier) { public static double getServerSpeedMultiplier() {
speedMultiplier = multiplier; return serverSpeedMultiplier;
}
public static double getSpeedMultiplier () {
return speedMultiplier;
} }
} }
@@ -37,9 +37,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60; private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
private boolean terminated; private boolean terminated;
private Thread thread; private Thread thread;
@@ -101,8 +98,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
GameState.addMessageEventListener(this::broadcastMessage); GameState.addMessageEventListener(this::broadcastMessage);
terminated = false; terminated = false;
thread = new Thread(this, "MainServer"); thread = new Thread(this, "MainServer");
startUpdatingWind();
startSpawningTokens();
thread.start(); thread.start();
} }
@@ -187,63 +182,6 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
private static void updateWind(){
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0){
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
}
else{
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED){
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED){
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind(){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
GameState.spawnNewToken();
broadcastMessage(MessageFactory.getRaceXML());
}
}, 10000, 60000);
}
/** /**
* A client has tried to connect to the server * A client has tried to connect to the server
* *
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage; import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.RaceStartNotificationType; import seng302.gameServer.messages.RaceStartNotificationType;
import seng302.gameServer.messages.RaceStartStatusMessage; import seng302.gameServer.messages.RaceStartStatusMessage;
import seng302.gameServer.messages.RaceStatus; import seng302.gameServer.messages.RaceStatus;
@@ -11,11 +12,14 @@ import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.messages.RaceType; import seng302.gameServer.messages.RaceType;
import seng302.gameServer.messages.XMLMessage; import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType; import seng302.gameServer.messages.XMLMessageSubType;
import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.gameServer.messages.YachtEventType;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.stream.xml.generator.RaceXMLTemplate; import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate; import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
/** /**
@@ -128,4 +132,73 @@ public class MessageFactory {
XMLMessageSubType.BOAT, XMLMessageSubType.BOAT,
xmlGenerator.getBoatsAsXml().length()); xmlGenerator.getBoatsAsXml().length());
} }
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
return new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION);
}
/**
* Constructs a message to be sent out whenever a yacht picks up a boost
*
* @param serverYacht The yacht that has picked up a power up
* @param token The token which they picked up
* @return The corresponding YachtEventCodeMessage
*/
public static YachtEventCodeMessage makePickupMessage(ServerYacht serverYacht, Token token) {
YachtEventType yachtEventType = null;
switch (token.getTokenType()) {
case BOOST:
yachtEventType = YachtEventType.TOKEN_VELOCITY;
break;
case HANDLING:
yachtEventType = YachtEventType.TOKEN_HANDLING;
break;
case WIND_WALKER:
yachtEventType = YachtEventType.TOKEN_WIND_WALKER;
break;
case BUMPER:
yachtEventType = YachtEventType.TOKEN_BUMPER;
break;
case RANDOM:
yachtEventType = YachtEventType.TOKEN_RANDOM;
break;
}
return new YachtEventCodeMessage(serverYacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message representing a certain buff / debuff for a given yacht. For now this is
* just for the bumper debuff so the affected boat is aware that it has been crashed. This could
* however be extended to render affects for all boats given a certain debuff.
*
* @param yacht The yacht affected by some status
* @param token The token indicating what status they have
* @return A YachtEventCodeMessage
*/
public static YachtEventCodeMessage makeStatusEffectMessage(ServerYacht yacht,
TokenType token) {
YachtEventType yachtEventType = null;
switch (token) {
case BUMPER:
yachtEventType = YachtEventType.BUMPER_CRASH;
break;
}
return new YachtEventCodeMessage(yacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message to be sent out when a given yacht powers down (From a boost of any type)
*
* @param yacht The yacht that is powering down
* @return A YachtEventCodeMessage representing this action
*/
public static YachtEventCodeMessage makePowerDownMessage(ServerYacht yacht) {
return new YachtEventCodeMessage(yacht.getSourceId(), YachtEventType.POWER_DOWN);
}
public static ChatterMessage makeChatterMessage(Integer messageType, String message) {
return new ChatterMessage(messageType, "SERVER: " + message);
}
} }
@@ -78,7 +78,6 @@ public class ServerToClientThread implements Runnable {
private List<ConnectionListener> connectionListeners = new ArrayList<>(); private List<ConnectionListener> connectionListeners = new ArrayList<>();
private DisconnectListener disconnectListener; private DisconnectListener disconnectListener;
private ServerYacht yacht;
private Player player; private Player player;
public ServerToClientThread(Socket socket) { public ServerToClientThread(Socket socket) {
@@ -101,33 +100,12 @@ public class ServerToClientThread implements Runnable {
} }
private void setUpPlayer(){ private void setUpPlayer(){
BufferedReader fn; String shortName = "p" + sourceId;
String fName = ""; String longName = "player " + sourceId;
BufferedReader ln;
String lName = "";
fn = new BufferedReader(
new InputStreamReader(
ServerToClientThread.class.getResourceAsStream(
"/server_config/CSV_Database_of_First_Names.csv"
)
)
);
List<String> all = fn.lines().collect(Collectors.toList());
fName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
ln = new BufferedReader(
new InputStreamReader(
ServerToClientThread.class.getResourceAsStream(
"/server_config/CSV_Database_of_Last_Names.csv"
)
)
);
all = ln.lines().collect(Collectors.toList());
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
ServerYacht yacht = new ServerYacht( ServerYacht yacht = new ServerYacht(
BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" BoatMeshType.DINGHY, sourceId, sourceId.toString(), shortName, longName, "NZ");
);
player = new Player(socket, yacht); player = new Player(socket, yacht);
GameState.addYacht(sourceId, yacht); GameState.addYacht(sourceId, yacht);
@@ -318,10 +296,6 @@ public class ServerToClientThread implements Runnable {
return socket; return socket;
} }
public ServerYacht getYacht() {
return yacht;
}
public void addConnectionListener(ConnectionListener listener) { public void addConnectionListener(ConnectionListener listener) {
connectionListeners.add(listener); connectionListeners.add(listener);
} }
@@ -5,19 +5,19 @@ package seng302.gameServer.messages;
*/ */
public class BoatActionMessage extends Message{ public class BoatActionMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION; private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
private final int MESSAGE_SIZE = 1; private final int MESSAGE_SIZE = 5;
private BoatAction actionType; private BoatAction actionType;
public BoatActionMessage(BoatAction actionType) { public BoatActionMessage(BoatAction actionType, int sourceId) {
this.actionType = actionType; this.actionType = actionType;
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id
allocateBuffer(); allocateBuffer();
writeHeaderToBuffer(); writeHeaderToBuffer();
// Write message fields // Write message fields
putInt(actionType.getValue(), 1); putInt(actionType.getValue(), 1);
putInt(sourceId, 4);
writeCRC(); writeCRC();
rewind(); rewind();
} }
@Override @Override
@@ -40,7 +40,7 @@ public class ChatterMessage extends Message {
return message; return message;
} }
public int getMessage_type() { public int getMessageType() {
return message_type; return message_type;
} }
} }
@@ -4,8 +4,8 @@ package seng302.gameServer.messages;
public class RegistrationRequestMessage extends Message { public class RegistrationRequestMessage extends Message {
private static int MESSAGE_LENGTH = 2; private static int MESSAGE_LENGTH = 2;
public RegistrationRequestMessage(ClientType type){ public RegistrationRequestMessage(ClientType type, int clientID){
setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize())); setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize()));
allocateBuffer(); allocateBuffer();
writeHeaderToBuffer(); writeHeaderToBuffer();
@@ -1,11 +1,18 @@
package seng302.gameServer.messages; package seng302.gameServer.messages;
/** /**
* Created by wmu16 on 11/09/17. * Enum for different event types for the yacht
*/ */
public enum YachtEventType { public enum YachtEventType {
COLLISION(33), COLLISION(33),
TOKEN(34); TOKEN_VELOCITY(34),
TOKEN_BUMPER(35),
TOKEN_HANDLING(36),
TOKEN_WIND_WALKER(37),
TOKEN_RANDOM(38),
POWER_DOWN(39),
BUMPER_CRASH(40);
private int code; private int code;
+97 -1
View File
@@ -6,16 +6,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Timer;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper; import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongProperty;
import javafx.beans.property.ReadOnlyLongWrapper; import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.beans.value.ObservableObjectValue;
import javafx.collections.FXCollections;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import jdk.nashorn.internal.objects.annotations.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/** /**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses) * Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
@@ -35,6 +41,26 @@ public class ClientYacht extends Observable {
void notifyRounding(ClientYacht yacht, int legNumber); void notifyRounding(ClientYacht yacht, int legNumber);
} }
@FunctionalInterface
public interface ColorChangeListener {
void notifyColorChange(ClientYacht yacht);
}
//This notifies RaceViewController so it can display icon - wmu16
@FunctionalInterface
public interface PowerUpListener {
void notifyPowerUp(ClientYacht yacht, TokenType tokenType);
}
//This notifies RaceViewController so it can remove token icon - wmu16
@FunctionalInterface
public interface PowerDownListener {
void notifyPowerDown(ClientYacht yacht);
}
private Logger logger = LoggerFactory.getLogger(ClientYacht.class); private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
@@ -45,6 +71,7 @@ public class ClientYacht extends Observable {
private String boatName; private String boatName;
private String country; private String country;
private Integer position; private Integer position;
private TokenType powerUp;
private Long estimateTimeAtFinish; private Long estimateTimeAtFinish;
private Boolean sailIn = true; private Boolean sailIn = true;
@@ -57,12 +84,21 @@ public class ClientYacht extends Observable {
private Integer boatStatus; private Integer boatStatus;
private Double currentVelocity; private Double currentVelocity;
Timer t;
private BoatObject boatObject;
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>(); private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private List<PowerUpListener> powerUpListeners = new ArrayList<>();
private List<PowerDownListener> powerDownListeners = new ArrayList<>();
private List<ColorChangeListener> colorChangeListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper(); private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
private Color colour; private Color colour;
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
@@ -75,6 +111,7 @@ public class ClientYacht extends Observable {
this.country = country; this.country = country;
this.location = new GeoPoint(57.670341, 11.826856); this.location = new GeoPoint(57.670341, 11.826856);
this.heading = 120.0; //In degrees this.heading = 120.0; //In degrees
this.headingProperty.set(this.heading);
this.currentVelocity = 0d; this.currentVelocity = 0d;
this.boatStatus = 1; this.boatStatus = 1;
this.colour = Color.rgb(0, 0, 0, 1.0); this.colour = Color.rgb(0, 0, 0, 1.0);
@@ -200,6 +237,32 @@ public class ClientYacht extends Observable {
this.position = position; this.position = position;
} }
/**
* Powers down the boat and notifies the raceViewController to display
*/
public void powerDown() {
this.powerUp = null;
for (PowerDownListener listener : powerDownListeners) {
listener.notifyPowerDown(this);
}
}
/**
* powers up the boat and notifies the raceViewController to display
*
* @param tokenType The type of token that this boat is being powered up with
*/
public void setPowerUp(TokenType tokenType) {
this.powerUp = tokenType;
for (PowerUpListener listener : powerUpListeners) {
listener.notifyPowerUp(this, tokenType);
}
}
public TokenType getPowerUp() {
return powerUp;
}
public void toggleSail() { public void toggleSail() {
sailIn = !sailIn; sailIn = !sailIn;
} }
@@ -222,6 +285,7 @@ public class ClientYacht extends Observable {
public void setHeading(Double heading) { public void setHeading(Double heading) {
this.heading = heading; this.heading = heading;
setHeadingProperty();
} }
@Override @Override
@@ -248,12 +312,15 @@ public class ClientYacht extends Observable {
public void setColour(Color colour) { public void setColour(Color colour) {
this.colour = colour; this.colour = colour;
for (ColorChangeListener listener : colorChangeListeners) {
listener.notifyColorChange(this);
}
} }
public void updateLocation(double lat, double lng, double heading, double velocity) { public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng); setLocation(lat, lng);
this.heading = heading; this.heading = heading;
setHeadingProperty();
this.currentVelocity = velocity; this.currentVelocity = velocity;
updateVelocityProperty(velocity); updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) { for (YachtLocationListener yll : locationListeners) {
@@ -261,6 +328,10 @@ public class ClientYacht extends Observable {
} }
} }
private void setHeadingProperty() {
headingProperty.set(heading);
}
public void addLocationListener(YachtLocationListener listener) { public void addLocationListener(YachtLocationListener listener) {
locationListeners.add(listener); locationListeners.add(listener);
} }
@@ -269,6 +340,18 @@ public class ClientYacht extends Observable {
markRoundingListeners.add(listener); markRoundingListeners.add(listener);
} }
public void addPowerUpListener(PowerUpListener listener) {
powerUpListeners.add(listener);
}
public void addPowerDownListener(PowerDownListener listener) {
powerDownListeners.add(listener);
}
public void addColorChangeListener(ColorChangeListener listener) {
colorChangeListeners.add(listener);
}
public void removeMarkRoundingListener(MarkRoundingListener listener) { public void removeMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.remove(listener); markRoundingListeners.remove(listener);
} }
@@ -289,4 +372,17 @@ public class ClientYacht extends Observable {
public Double getCurrentVelocity() { public Double getCurrentVelocity() {
return currentVelocity; return currentVelocity;
} }
public void setBoatObject(BoatObject newBoatObject) {
this.boatObject = newBoatObject;
}
public BoatObject getBoatObject() {
return this.boatObject;
}
public ReadOnlyDoubleWrapper getHeadingProperty() {
return headingProperty;
}
} }
+10 -1
View File
@@ -30,7 +30,12 @@ public class GameKeyBind {
keys.add(KeyCode.ENTER); keys.add(KeyCode.ENTER);
keys.add(KeyCode.PAGE_UP); keys.add(KeyCode.PAGE_UP);
keys.add(KeyCode.PAGE_DOWN); keys.add(KeyCode.PAGE_DOWN);
for (int i = 0; i < 7; i++) { keys.add(KeyCode.F1);
keys.add(KeyCode.D);
keys.add(KeyCode.A);
keys.add(KeyCode.W);
keys.add(KeyCode.S);
for (int i = 0; i < 12; i++) {
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i)); actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1)); keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
} }
@@ -47,6 +52,10 @@ public class GameKeyBind {
return instance.actionToKeyMap.get(keyAction); return instance.actionToKeyMap.get(keyAction);
} }
public KeyAction getKeyAction(KeyCode keyCode) {
return instance.keyToActionMap.get(keyCode);
}
/** /**
* Binds a key to a key action * Binds a key to a key action
* *
+6 -1
View File
@@ -10,7 +10,12 @@ public enum KeyAction {
SAILS_STATE(4), SAILS_STATE(4),
TACK_GYBE(5), TACK_GYBE(5),
UPWIND(6), UPWIND(6),
DOWNWIND(7); DOWNWIND(7),
VIEW(8),
RIGHT(9),
LEFT(10),
FORWARD(11),
BACKWARD(12);
private final int type; private final int type;
private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>(); private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>();
+37 -4
View File
@@ -4,7 +4,9 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
/** /**
* A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised * A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised
@@ -17,6 +19,7 @@ public final class PolarTable {
private static HashMap<Double, HashMap<Double, Double>> polarTable; private static HashMap<Double, HashMap<Double, Double>> polarTable;
private static HashMap<Double, HashMap<Double, Double>> upwindOptimal; private static HashMap<Double, HashMap<Double, Double>> upwindOptimal;
private static HashMap<Double, HashMap<Double, Double>> downwindOptimal; private static HashMap<Double, HashMap<Double, Double>> downwindOptimal;
private static Double optimalAngle;
private static int upTwaIndex; private static int upTwaIndex;
private static int dnTwaIndex; private static int dnTwaIndex;
@@ -33,11 +36,13 @@ public final class PolarTable {
upwindOptimal = new HashMap<>(); upwindOptimal = new HashMap<>();
downwindOptimal = new HashMap<>(); downwindOptimal = new HashMap<>();
String line; String line = null;
String check;
Boolean isHeaderLine = true; Boolean isHeaderLine = true;
try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) { try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) {
while ((line = br.readLine()) != null) { while ((check = br.readLine()) != null) {
line = check;
String[] thisLine = line.split(","); String[] thisLine = line.split(",");
//Initial line in file //Initial line in file
@@ -66,7 +71,10 @@ public final class PolarTable {
upwindOptimal.put(thisWindSpeed, thisUpWindPolar); upwindOptimal.put(thisWindSpeed, thisUpWindPolar);
downwindOptimal.put(thisWindSpeed, thisDnWindPolar); downwindOptimal.put(thisWindSpeed, thisDnWindPolar);
} }
} }
getMaxSpeedAngle(line);
} catch (IOException e) { } catch (IOException e) {
System.out.println("[PolarTable] IO exception"); System.out.println("[PolarTable] IO exception");
@@ -74,6 +82,27 @@ public final class PolarTable {
} }
/**
* Passes the final line of the polar table and iterates over the speeds for each
* angle, velocity pair to find the angle that produces the highest velocity
*
* @param line The last line of the polar file
*/
private static void getMaxSpeedAngle(String line) {
String[] theLastLine = line.split(",");
Double maxWindVal = Double.parseDouble(theLastLine[0]);
Double optimalAngle = Double.parseDouble(theLastLine[1]);
Double maxSpeed = Double.parseDouble(theLastLine[2]);
for (Map.Entry<Double, Double> entry : polarTable.get(maxWindVal).entrySet()) {
if (entry.getValue() > maxSpeed) {
maxSpeed = entry.getValue();
optimalAngle = entry.getKey();
}
}
PolarTable.optimalAngle = optimalAngle;
}
/** /**
* Parses the header line of a polar file * Parses the header line of a polar file
@@ -85,14 +114,18 @@ public final class PolarTable {
String thisItem = thisLine[i]; String thisItem = thisLine[i];
if (thisItem.toLowerCase().startsWith("uptwa")) { if (thisItem.toLowerCase().startsWith("uptwa")) {
upTwaIndex = i; upTwaIndex = i;
} } else if (thisItem.toLowerCase().startsWith("dntwa")) {
else if (thisItem.toLowerCase().startsWith("dntwa")) {
dnTwaIndex = i; dnTwaIndex = i;
} }
} }
} }
public static Double getOptimalAngle() {
return optimalAngle;
}
/** /**
* @return The entire polar table * @return The entire polar table
*/ */
+57 -18
View File
@@ -23,9 +23,9 @@ public class ServerYacht {
//Boat info //Boat info
private BoatMeshType boatType; private BoatMeshType boatType;
private Double turnStep = 5.0; private Double turnStep = 5.0;
private Double maxSpeedMultiplier = 1.0; private Double boatTypeSpeedMultiplier = 1.0;
private Double turnStepMultiplier = 1.0; private Double boatTypeTurnStepMultiplier = 1.0;
private Double accelerationMultiplier = 1.0; private Double boatTypeAccelerationMultiplier = 1.0;
private Integer sourceId; private Integer sourceId;
private String hullID; //matches HullNum in the XML spec. private String hullID; //matches HullNum in the XML spec.
private String shortName; private String shortName;
@@ -55,6 +55,8 @@ public class ServerYacht {
//PowerUp //PowerUp
private TokenType powerUp; private TokenType powerUp;
private Long powerUpStartTime; private Long powerUpStartTime;
private Double powerUpSpeedMultiplier;
private Integer powerUpHandlingMultiplier;
//turning mode //turning mode
private Boolean continuouslyTurning; private Boolean continuouslyTurning;
@@ -78,11 +80,11 @@ public class ServerYacht {
this.legNumber = 0; this.legNumber = 0;
this.boatColor = Colors.getColor(sourceId - 1); this.boatColor = Colors.getColor(sourceId - 1);
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
this.hasEnteredRoundingZone = false; this.hasEnteredRoundingZone = false;
this.hasPassedLine = false; this.hasPassedLine = false;
this.hasPassedThroughGate = false; this.hasPassedThroughGate = false;
this.continuouslyTurning = false; this.continuouslyTurning = false;
} }
@@ -110,13 +112,33 @@ public class ServerYacht {
location = geoPoint; location = geoPoint;
} }
/**
* Powers up a yacht with a given yacht, only after powering it down first to avoid double power
* ups
*
* @param powerUp The given power up
*/
public void powerUp(TokenType powerUp) { public void powerUp(TokenType powerUp) {
powerDown();
switch (powerUp) {
case BOOST:
powerUpSpeedMultiplier = GameState.VELOCITY_BOOST_MULTIPLIER;
break;
case HANDLING:
powerUpHandlingMultiplier = GameState.HANDLING_BOOST_MULTIPLIER;
break;
}
this.powerUp = powerUp; this.powerUp = powerUp;
powerUpStartTime = System.currentTimeMillis(); powerUpStartTime = System.currentTimeMillis();
} }
/**
* Powers down a yacht, returning its power multipliers back to 1
*/
public void powerDown() { public void powerDown() {
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
} }
public Long getPowerUpStartTime() { public Long getPowerUpStartTime() {
@@ -133,7 +155,7 @@ public class ServerYacht {
* @param amount the amount by which to adjust the boat heading. * @param amount the amount by which to adjust the boat heading.
*/ */
public void adjustHeading(Double amount) { public void adjustHeading(Double amount) {
Double newVal = heading + (amount * turnStepMultiplier); Double newVal = heading + amount * powerUpHandlingMultiplier * boatTypeTurnStepMultiplier;
lastHeading = heading; lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L); heading = (double) Math.floorMod(newVal.longValue(), 360L);
} }
@@ -156,11 +178,11 @@ public class ServerYacht {
/** /**
* Enables the boats auto pilot feature, which will move the boat towards a given heading. * Enables the boats auto pilot feature, which will move the boat towards a given heading.
* *
* @param thisHeading The heading to move the boat towards. * @param newHeading The heading to move the boat towards.
*/ */
private void setAutoPilot(Double thisHeading) { private void setAutoPilot(Double newHeading) {
isAuto = true; isAuto = true;
autoHeading = thisHeading; autoHeading = newHeading;
} }
/** /**
@@ -178,8 +200,9 @@ public class ServerYacht {
if (isAuto) { if (isAuto) {
turnTowardsHeading(autoHeading); turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading) if (Math.abs(heading - autoHeading)
<= turnStep) { //Cancel when within 1 turn step of target. <= turnStep*1.5) {
isAuto = false; isAuto = false;
setHeading(autoHeading);
} }
} }
} }
@@ -265,7 +288,7 @@ public class ServerYacht {
// Take optimal heading and turn into a boat heading rather than a wind heading. // Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading = optimalHeading =
optimalHeading + GameState.getWindDirection(); (optimalHeading + GameState.getWindDirection()) % 360;
setAutoPilot(optimalHeading); setAutoPilot(optimalHeading);
} }
@@ -434,18 +457,18 @@ public class ServerYacht {
} }
public void setBoatType(BoatMeshType boatType) { public void setBoatType(BoatMeshType boatType) {
this.accelerationMultiplier = boatType.accelerationMultiplier; this.boatTypeAccelerationMultiplier = boatType.accelerationMultiplier;
this.maxSpeedMultiplier = boatType.maxSpeedMultiplier; this.boatTypeSpeedMultiplier = boatType.maxSpeedMultiplier;
this.turnStepMultiplier = boatType.turnStep; this.boatTypeTurnStepMultiplier = boatType.turnStep;
this.boatType = boatType; this.boatType = boatType;
} }
public Double getMaxSpeedMultiplier() { public Double getBoatTypeSpeedMultiplier() {
return maxSpeedMultiplier; return boatTypeSpeedMultiplier;
} }
public Double getAccelerationMultiplier(){ public Double getBoatTypeAccelerationMultiplier() {
return accelerationMultiplier; return boatTypeAccelerationMultiplier;
} }
@@ -456,4 +479,20 @@ public class ServerYacht {
public void setContinuouslyTurning(Boolean continuouslyTurning) { public void setContinuouslyTurning(Boolean continuouslyTurning) {
this.continuouslyTurning = continuouslyTurning; this.continuouslyTurning = continuouslyTurning;
} }
public Double getPowerUpSpeedMultiplier() {
return powerUpSpeedMultiplier;
}
public void setPowerUpSpeedMultiplier(Double powerUpSpeedMultiplier) {
this.powerUpSpeedMultiplier = powerUpSpeedMultiplier;
}
public Integer getPowerUpHandlingMultiplier() {
return powerUpHandlingMultiplier;
}
public void setPowerUpHandlingMultiplier(Integer powerUpHandlingMultiplier) {
this.powerUpHandlingMultiplier = powerUpHandlingMultiplier;
}
} }
@@ -24,8 +24,9 @@ import java.util.*;
*/ */
public class MarkOrder { public class MarkOrder {
private List<CompoundMark> raceMarkOrder; private List<CompoundMark> raceMarkOrder;
private List<CompoundMark> orderedUniqueCompoundMarks;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class); private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
private Set<Mark> allMarks; private List<Mark> allMarks;
public MarkOrder(){ public MarkOrder(){
loadRaceProperties(); loadRaceProperties();
@@ -44,6 +45,10 @@ public class MarkOrder {
return Collections.unmodifiableList(raceMarkOrder); return Collections.unmodifiableList(raceMarkOrder);
} }
public List<CompoundMark> getOrderedUniqueCompoundMarks() {
return orderedUniqueCompoundMarks;
}
/** /**
* @param seqID The seqID of the current mark the boat is heading to * @param seqID The seqID of the current mark the boat is heading to
* @return A Boolean indicating if this coming mark is the last one (finish line) * @return A Boolean indicating if this coming mark is the last one (finish line)
@@ -75,8 +80,8 @@ public class MarkOrder {
return raceMarkOrder.get(currentSeqID + 1); return raceMarkOrder.get(currentSeqID + 1);
} }
public Set<Mark> getAllMarks(){ public List<Mark> getAllMarks() {
return Collections.unmodifiableSet(allMarks); return Collections.unmodifiableList(allMarks);
} }
/** /**
@@ -89,7 +94,7 @@ public class MarkOrder {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db; DocumentBuilder db;
Document doc; Document doc;
allMarks = new HashSet<>(); allMarks = new ArrayList<>();
try { try {
db = dbf.newDocumentBuilder(); db = dbf.newDocumentBuilder();
@@ -105,6 +110,7 @@ public class MarkOrder {
logger.debug("Loaded RaceXML for mark order"); logger.debug("Loaded RaceXML for mark order");
List<Corner> corners = data.getMarkSequence(); List<Corner> corners = data.getMarkSequence();
Map<Integer, CompoundMark> marks = data.getCompoundMarks(); Map<Integer, CompoundMark> marks = data.getCompoundMarks();
orderedUniqueCompoundMarks = new ArrayList<>(marks.values());
List<CompoundMark> course = new ArrayList<>(); List<CompoundMark> course = new ArrayList<>();
for (Corner corner : corners){ for (Corner corner : corners){
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID()); CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
@@ -1,5 +1,9 @@
package seng302.model.token; package seng302.model.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
/** /**
@@ -9,13 +13,50 @@ import seng302.model.GeoPoint;
public class Token extends GeoPoint { public class Token extends GeoPoint {
private TokenType tokenType; private TokenType tokenType;
private Random random = new Random();
//Constructor for creating a specific type client side
public Token(TokenType tokenType, double lat, double lng) { public Token(TokenType tokenType, double lat, double lng) {
super(lat, lng); super(lat, lng);
this.tokenType = tokenType; this.tokenType = tokenType;
} }
//Making random type server side
public Token(double lat, double lng) {
super(lat, lng);
assignRandomType();
}
//Making random type server side
public Token(GeoPoint geoPoint) {
super(geoPoint.getLat(), geoPoint.getLng());
assignRandomType();
}
public TokenType getTokenType() { public TokenType getTokenType() {
return tokenType; return tokenType;
} }
/**
* Assigns a random type to the token (including the random type token)
*/
public void assignRandomType() {
tokenType = TokenType.values()[random.nextInt(TokenType.values().length)];
}
/**
* Assigns a random, concrete type to the token (cannot be the random type)
*/
public void realiseRandom() {
List<TokenType> tokenTypeList = new ArrayList<>(Arrays.asList(TokenType.values()));
tokenTypeList.remove(TokenType.RANDOM);
tokenType = tokenTypeList.get(random.nextInt(tokenTypeList.size()));
}
/**
* Exists for testing purposes only
*/
public void assignType(TokenType tokenType) {
this.tokenType = tokenType;
}
} }
@@ -5,27 +5,32 @@ package seng302.model.token;
* Created by wmu16 on 28/08/17. * Created by wmu16 on 28/08/17.
*/ */
public enum TokenType { public enum TokenType {
BOOST(0),
HANDLING(1); BOOST(0, "Boost", 10_000),
HANDLING(1, "Handling", 10_000),
BUMPER(2, "Bumper", 10_000),
WIND_WALKER(3, "Wind Walker", 10_000),
RANDOM(4, "Random", 10_000);
private int value; private int value;
private String name;
private int timeout;
TokenType(int value) { TokenType(int value, String name, int timeout) {
this.value = value; this.value = value;
this.name = name;
this.timeout = timeout;
} }
public int getValue() { public int getValue() {
return value; return value;
} }
public static TokenType getToken(int value) { public String getName() {
switch (value) { return name;
case 0: }
return BOOST;
case 1: public int getTimeout() {
return HANDLING; return timeout;
default:
return BOOST;
}
} }
} }
@@ -0,0 +1,63 @@
package seng302.utilities;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.token.Token;
/**
* A class for generating and spawning tokens in random locations
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawn {
private static final Integer DEGREES_IN_CIRCLE = 360;
private HashMap<GeoPoint, Double> spawnRadii;
private Random random;
/**
* @param markOrder this must be the ORDERED list of marks. Better yet UNIQUE to avoid over
* computation
*/
public RandomSpawn(List<CompoundMark> markOrder) {
this.spawnRadii = new HashMap<>();
random = new Random();
spawnRadii = generateSpawnRadii(markOrder);
}
private HashMap<GeoPoint, Double> generateSpawnRadii(List<CompoundMark> markOrder) {
HashMap<GeoPoint, Double> spawnRadii = new HashMap<>();
for (int i = 0; i < markOrder.size() - 1; i++) {
GeoPoint spawnCentre = GeoUtility.getDirtyMidPoint(
markOrder.get(i).getMidPoint(),
markOrder.get(i + 1).getMidPoint());
Double distance = GeoUtility.getDistance(spawnCentre, markOrder.get(i).getMidPoint());
spawnRadii.put(spawnCentre, distance);
}
return spawnRadii;
}
/**
* @return A random token type at a random location in a random radii of the set of possible
* radii
*/
public Token getRandomTokenLocation() {
Object[] keys = spawnRadii.keySet().toArray();
GeoPoint randomSpawnCentre = (GeoPoint) keys[random.nextInt(keys.length)];
Double spawnRadius = spawnRadii.get(randomSpawnCentre);
Double randomDistance = spawnRadius * random.nextDouble();
Double randomAngle = random.nextDouble() * DEGREES_IN_CIRCLE;
GeoPoint randomLocation = GeoUtility
.getGeoCoordinate(randomSpawnCentre, randomAngle, randomDistance);
return new Token(randomLocation);
}
}
+28 -11
View File
@@ -4,12 +4,14 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.Colors;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
@@ -139,14 +141,26 @@ public class XMLParser {
Node currentBoat = boatsList.item(i); Node currentBoat = boatsList.item(i);
if (currentBoat.getNodeName().equals("Boat")) { if (currentBoat.getNodeName().equals("Boat")) {
// Boat boat = new Boat(currentBoat); // Boat boat = new Boat(currentBoat);
BoatMeshType boatMeshType;
try {
boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type"));
} catch (IllegalArgumentException e){
boatMeshType = BoatMeshType.DINGHY;
}
Color color;
try {
color = Color.web(getNodeAttributeString(currentBoat, "Color"));
} catch (NullPointerException npe) {
color = Colors.getColor(new Random().nextInt(8));
}
ClientYacht yacht = new ClientYacht( ClientYacht yacht = new ClientYacht(
BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")), boatMeshType,
XMLParser.getNodeAttributeInt(currentBoat, "SourceID"), XMLParser.getNodeAttributeInt(currentBoat, "SourceID"),
XMLParser.getNodeAttributeString(currentBoat, "HullNum"), XMLParser.getNodeAttributeString(currentBoat, "HullNum"),
XMLParser.getNodeAttributeString(currentBoat, "ShortName"), XMLParser.getNodeAttributeString(currentBoat, "ShortName"),
XMLParser.getNodeAttributeString(currentBoat, "BoatName"), XMLParser.getNodeAttributeString(currentBoat, "BoatName"),
XMLParser.getNodeAttributeString(currentBoat, "Country")); XMLParser.getNodeAttributeString(currentBoat, "Country"));
yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color"))); yacht.setColour(color);
competingBoats.put(yacht.getSourceId(), yacht); competingBoats.put(yacht.getSourceId(), yacht);
} }
} }
@@ -195,17 +209,20 @@ public class XMLParser {
*/ */
private static List<Token> extractTokens(Element docEle) { private static List<Token> extractTokens(Element docEle) {
List<Token> tokens = new ArrayList<>(); List<Token> tokens = new ArrayList<>();
NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); try {
for (int i = 0; i < tokenList.getLength(); i++) { NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes();
Node tokenNode = tokenList.item(i); for (int i = 0; i < tokenList.getLength(); i++) {
if (tokenNode.getNodeName().equals("Token")) { Node tokenNode = tokenList.item(i);
String tokenType = getNodeAttributeString(tokenNode, "TokenType"); if (tokenNode.getNodeName().equals("Token")) {
Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); String tokenType = getNodeAttributeString(tokenNode, "TokenType");
Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); Double lat = getNodeAttributeDouble(tokenNode, "TargetLat");
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng)); Double lng = getNodeAttributeDouble(tokenNode, "TargetLng");
tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng));
}
} }
} catch (NullPointerException npe) {
return new ArrayList<>();
} }
return tokens; return tokens;
} }
@@ -175,7 +175,7 @@ public class ClientToServerThread implements Runnable {
* Sends a request to the server asking for a source ID * Sends a request to the server asking for a source ID
*/ */
private void sendRegistrationRequest() { private void sendRegistrationRequest() {
RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER); RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId);
try { try {
os.write(requestMessage.getBuffer()); os.write(requestMessage.getBuffer());
@@ -193,7 +193,6 @@ public class ClientToServerThread implements Runnable {
private void processRegistrationResponse(StreamPacket packet){ private void processRegistrationResponse(StreamPacket packet){
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3)); int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3));
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5)); int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode); RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){ if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){
@@ -243,7 +242,7 @@ public class ClientToServerThread implements Runnable {
new TimerTask() { new TimerTask() {
@Override @Override
public void run() { public void run() {
sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND)); sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId));
} }
}, 0, PACKET_SENDING_INTERVAL_MS }, 0, PACKET_SENDING_INTERVAL_MS
); );
@@ -256,14 +255,14 @@ public class ClientToServerThread implements Runnable {
new TimerTask() { new TimerTask() {
@Override @Override
public void run() { public void run() {
sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND)); sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId));
} }
}, 0, PACKET_SENDING_INTERVAL_MS }, 0, PACKET_SENDING_INTERVAL_MS
); );
} }
break; break;
default: default:
sendBoatActionMessage(new BoatActionMessage(actionType)); sendBoatActionMessage(new BoatActionMessage(actionType, clientId));
break; break;
} }
} }
@@ -10,15 +10,16 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
@@ -39,6 +40,7 @@ import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.parser.YachtEventData; import seng302.model.stream.parser.YachtEventData;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.utilities.StreamParser; import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
@@ -46,6 +48,7 @@ import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController; import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
@@ -169,10 +172,12 @@ public class GameClient {
private void showConnectionError (String message) { private void showConnectionError (String message) {
Platform.runLater(() -> { Platform.runLater(() -> {
Alert alert = new Alert(AlertType.ERROR); PopupDialogController controller = ViewManager.getInstance().showPopupDialog();
alert.setHeaderText("Connection Error"); controller.setHeader("Oops");
alert.setContentText(message); controller.setContent(message);
alert.showAndWait(); controller.setOptionButtonText("GO HOME");
controller
.setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView());
}); });
} }
@@ -250,12 +255,7 @@ public class GameClient {
break; break;
case YACHT_EVENT_CODE: case YACHT_EVENT_CODE:
YachtEventData yachtEventData = StreamParser.extractYachtEventCode(packet); processYachtEvent(StreamParser.extractYachtEventCode(packet));
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN.getCode()) {
showPickUp();
}
break; break;
case CHATTER_TEXT: case CHATTER_TEXT:
@@ -398,7 +398,11 @@ public class GameClient {
} }
if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out
socketThread.sendBoatAction(BoatAction.SAILS_IN); if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) {
socketThread.sendBoatAction(BoatAction.SAILS_OUT);
} else {
socketThread.sendBoatAction(BoatAction.SAILS_IN);
}
allBoatsMap.get(socketThread.getClientId()).toggleSail(); allBoatsMap.get(socketThread.getClientId()).toggleSail();
} else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()
|| gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { || gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) {
@@ -410,21 +414,66 @@ public class GameClient {
return courseData; return courseData;
} }
/**
* Appropriately displays the event client side given the YachtEventCode (collision / token..)
*
* @param yachtEventData The YachtEvent data packet
*/
private void processYachtEvent(YachtEventData yachtEventData) {
ClientYacht thisYacht = allBoatsMap.get(yachtEventData.getSubjectId().intValue());
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(thisYacht);
} else if (yachtEventData.getEventId() == YachtEventType.POWER_DOWN.getCode()) {
thisYacht.powerDown();
Sounds.playTokenPickupSound(); // TODO: 23/09/17 This should be power down sound
} else if (yachtEventData.getEventId() == YachtEventType.BUMPER_CRASH.getCode()) {
showDisableAlert(thisYacht);
} else { //Else all token pickup types
TokenType tokenType = null;
if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) {
tokenType = TokenType.BOOST;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_BUMPER.getCode()) {
tokenType = TokenType.BUMPER;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_HANDLING.getCode()) {
tokenType = TokenType.HANDLING;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_RANDOM.getCode()) {
tokenType = TokenType.RANDOM;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_WIND_WALKER.getCode()) {
tokenType = TokenType.WIND_WALKER;
}
Sounds.playTokenPickupSound();
thisYacht.setPowerUp(tokenType);
}
}
/**
* Turns a disabled boat black until the bumper affect wears off
*
* @param yacht The yacht to show as disabled
*/
private void showDisableAlert(ClientYacht yacht) {
Color originalColor = yacht.getColour();
yacht.setColour(Color.BLACK);
Timer disableTimer = new Timer("Disable Timer");
disableTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.setColour(originalColor);
}
}, GameState.BUMPER_DISABLE_TIME);
}
/** /**
* Tells race view to show a collision animation. * Tells race view to show a collision animation.
*/ */
private void showCollisionAlert(YachtEventData yachtEventData) { private void showCollisionAlert(ClientYacht yacht) {
Sounds.playCrashSound(); Sounds.playCrashSound();
raceState.storeCollision( raceState.storeCollision(yacht);
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
}
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
private void showPickUp() {
Sounds.playTokenPickupSound();
} }
private void formatAndSendChatMessage(String rawChat) { private void formatAndSendChatMessage(String rawChat) {
+111 -53
View File
@@ -1,6 +1,7 @@
package seng302.visualiser; package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -9,6 +10,7 @@ import javafx.animation.AnimationTimer;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
@@ -21,16 +23,23 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.GameKeyBind;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.KeyAction;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.cameras.ChaseCamera;
import seng302.visualiser.cameras.IsometricCamera;
import seng302.visualiser.cameras.RaceCamera;
import seng302.visualiser.cameras.TopDownCamera;
import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.fxObjects.MarkArrowFactory; import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
import seng302.visualiser.fxObjects.assets_3D.Marker3D; import seng302.visualiser.fxObjects.assets_3D.Marker3D;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory; import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
@@ -42,18 +51,19 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class GameView3D { public class GameView3D {
private final double FOV = 60; private final double FOV = 60;
private final double DEFAULT_CAMERA_DEPTH = -125;
private final double DEFAULT_CAMERA_X = 0; private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 155; private final double DEFAULT_CAMERA_Y = 155;
private Group root3D; private Group root3D;
private SubScene view; private SubScene view;
// ParallelCamera camera;
private PerspectiveCamera camera;
private Group gameObjects; private Group gameObjects;
// Cameras
private PerspectiveCamera isometricCam;
private PerspectiveCamera topDownCam;
private PerspectiveCamera chaseCam;
private double bufferSize = 0; private double bufferSize = 0;
private double canvasWidth = 200; private double canvasWidth = 200;
private double canvasHeight = 200; private double canvasHeight = 200;
@@ -88,20 +98,22 @@ public class GameView3D {
} }
public GameView3D () { public GameView3D () {
camera = new PerspectiveCamera(true); isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
camera.getTransforms().addAll( topDownCam = new TopDownCamera();
new Translate(DEFAULT_CAMERA_X,DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH) chaseCam = new ChaseCamera();
);
camera.setFarClip(600); for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
camera.setNearClip(0.1); pc.setFarClip(600);
camera.setFieldOfView(FOV); pc.setNearClip(0.1);
pc.setFieldOfView(FOV);
}
gameObjects = new Group(); gameObjects = new Group();
root3D = new Group(camera, gameObjects); root3D = new Group(isometricCam, gameObjects);
view = new SubScene( view = new SubScene(
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
); );
view.setCamera(camera); view.setCamera(isometricCam);
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
gameObjects.getChildren().addAll( gameObjects.getChildren().addAll(
ModelFactory.importModel(ModelType.OCEAN).getAssets(), ModelFactory.importModel(ModelType.OCEAN).getAssets(),
@@ -336,7 +348,6 @@ public class GameView3D {
* it to distanceScaleFactor Returns the max horizontal distance of the map. * it to distanceScaleFactor Returns the max horizontal distance of the map.
*/ */
private double scaleRaceExtremities() { private double scaleRaceExtremities() {
double vertAngle = Math.abs( double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint) GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
); );
@@ -404,37 +415,44 @@ public class GameView3D {
} }
public void cameraMovement(KeyEvent event) { public void cameraMovement(KeyEvent event) {
switch (event.getCode()) { GameKeyBind keyBinds = GameKeyBind.getInstance();
case NUMPAD8: KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(1,0,0))); if (keyPressed != null) {
break; switch (keyPressed) {
case NUMPAD2: case ZOOM_IN:
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(1,0,0))); ((RaceCamera) view.getCamera()).zoomIn();
break; break;
case NUMPAD4: case ZOOM_OUT:
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(0,1,0))); ((RaceCamera) view.getCamera()).zoomOut();
break; break;
case NUMPAD6: case FORWARD:
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0))); ((RaceCamera) view.getCamera()).panUp();
break; break;
case Z: case BACKWARD:
camera.getTransforms().addAll(new Translate(0, 0, 1.5)); ((RaceCamera) view.getCamera()).panDown();
break; break;
case X: case LEFT:
camera.getTransforms().addAll(new Translate(0, 0, -1.5)); ((RaceCamera) view.getCamera()).panLeft();
break; break;
case W: case RIGHT:
camera.getTransforms().addAll(new Translate(0, -1, 0)); ((RaceCamera) view.getCamera()).panRight();
break; break;
case S: case VIEW:
camera.getTransforms().addAll(new Translate(0, 1, 0)); toggleCamera();
break; break;
case A: }
camera.getTransforms().addAll(new Translate(-1, 0, 0)); }
break; }
case D:
camera.getTransforms().addAll(new Translate(1, 0, 0)); private void toggleCamera() {
break; Camera currCamera = view.getCamera();
if (currCamera.equals(isometricCam)) {
view.setCamera(topDownCam);
} else if (currCamera.equals(topDownCam)) {
view.setCamera(chaseCam);
} else {
view.setCamera(isometricCam);
} }
} }
@@ -466,11 +484,14 @@ public class GameView3D {
wakesGroup.getChildren().add(newBoat.getWake()); wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake()); wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> { clientYacht.addLocationListener(this::updateBoatLocation);
BoatObject bo = boatObjects.get(boat); clientYacht.addColorChangeListener(this::updateBoatColor);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir); if (clientYacht.getSourceId().equals(
}); ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
((ChaseCamera) chaseCam).setPlayerBoat(newBoat);
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
}
} }
Platform.runLater(() -> { Platform.runLater(() -> {
gameObjects.getChildren().addAll(wakes); gameObjects.getChildren().addAll(wakes);
@@ -482,6 +503,23 @@ public class GameView3D {
return view; return view;
} }
/**
* Updates the boatObjects color with that of the clientYachts object. Used in notification from
* a listener on this attribute in clientYacht to re paint the boat mesh
*
* @param clientYacht The yacht to update the colour for
*/
private void updateBoatColor(ClientYacht clientYacht) {
boatObjects.get(clientYacht).setFill(clientYacht.getColour());
}
private void updateBoatLocation(ClientYacht boat, Double lat, Double lon, Double heading,
Boolean sailIn, Double velocity) {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
}
/** /**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a * Adds a border to the GameView and rescales to the size of the border, does not rescale if a
* border already exists. Assumes the border is larger than the course. * border already exists. Assumes the border is larger than the course.
@@ -557,7 +595,27 @@ public class GameView3D {
mapTokens = new ArrayList<>(); mapTokens = new ArrayList<>();
for (Token token : newTokens) { for (Token token : newTokens) {
Point2D location = findScaledXY(token.getLat(), token.getLng()); Point2D location = findScaledXY(token.getLat(), token.getLng());
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
ModelType modelType = null;
switch (token.getTokenType()) {
case BOOST:
modelType = ModelType.VELOCITY_PICKUP;
break;
case HANDLING:
modelType = ModelType.HANDLING_PICKUP;
break;
case BUMPER:
modelType = ModelType.BUMPER_PICKUP;
break;
case RANDOM:
modelType = ModelType.RANDOM_PICKUP;
break;
case WIND_WALKER:
modelType = ModelType.WIND_WALKER_PICKUP;
break;
}
Node tokenObject = ModelFactory.importModel(modelType).getAssets();
tokenObject.setLayoutX(location.getX()); tokenObject.setLayoutX(location.getX());
tokenObject.setLayoutY(location.getY()); tokenObject.setLayoutY(location.getY());
mapTokens.add(tokenObject); mapTokens.add(tokenObject);
@@ -0,0 +1,130 @@
package seng302.visualiser.cameras;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
private final Double VERTICAL_PAN_LIMIT = 20.0;
private final Double NEAR_ZOOM_LIMIT = -15.0;
private final Double FAR_ZOOM_LIMIT = -125.0;
private final Double ZOOM_STEP = 2.5;
private final Double PAN_STEP = 2.5;
private ObservableList<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public ChaseCamera() {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
this.horizontalPan = 0.0;
this.verticalPan = 0.0;
}
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays
.asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(),
playerBoat.layoutXProperty())) {
o.addListener((obs, oldVal, newVal) -> repositionCamera());
}
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void repositionCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), 0),
new Rotate(playerBoat.getRotationProperty().getValue() + horizontalPan,
new Point3D(0, 0, 1)),
new Rotate(60 + verticalPan, new Point3D(1, 0, 0)),
new Translate(0, 0, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
repositionCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -VERTICAL_PAN_LIMIT
&& verticalPan + adjustment <= VERTICAL_PAN_LIMIT) {
verticalPan += adjustment;
repositionCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
this.horizontalPan += adjustment;
repositionCamera();
}
@Override
public void zoomIn() {
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP);
}
@Override
public void panLeft() {
adjustHorizontalPan(-PAN_STEP);
}
@Override
public void panRight() {
adjustHorizontalPan(PAN_STEP);
}
@Override
public void panUp() {
adjustVerticalPan(-PAN_STEP);
}
@Override
public void panDown() {
adjustVerticalPan(PAN_STEP);
}
}
@@ -0,0 +1,113 @@
package seng302.visualiser.cameras;
import javafx.collections.ObservableList;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
private final Double MIN_X = -120.0;
private final Double MAX_X = 125.0;
private final Double MIN_Y = 40.0;
private final Double MAX_Y = 170.0;
private final Double PAN_LIMIT = 160.0;
private final Double NEAR_ZOOM_LIMIT = -50.0;
private final Double FAR_ZOOM_LIMIT = -160.0;
private Double horizontalPan;
private Double verticalPan;
private Double zoomFactor;
private ObservableList<Transform> transforms;
public IsometricCamera(Double cameraStartX, Double cameraStartY) {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = cameraStartX;
verticalPan = cameraStartY;
updateCamera();
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(horizontalPan, verticalPan, zoomFactor),
new Rotate(30, new Point3D(1, 0, 0))
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
*
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= MIN_Y && verticalPan + adjustment <= MAX_Y) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= MIN_X && horizontalPan + adjustment <= MIN_Y) {
this.horizontalPan += adjustment;
updateCamera();
}
}
@Override
public void zoomIn() {
adjustZoomFactor(-2.5);
}
@Override
public void zoomOut() {
adjustZoomFactor(2.5);
}
@Override
public void panLeft() {
adjustHorizontalPan(-2.5);
}
@Override
public void panRight() {
adjustHorizontalPan(2.5);
}
@Override
public void panUp() {
adjustVerticalPan(-2.5);
}
@Override
public void panDown() {
adjustVerticalPan(2.5);
}
}
@@ -0,0 +1,18 @@
package seng302.visualiser.cameras;
public interface RaceCamera {
void zoomIn();
void zoomOut();
void panLeft();
void panRight();
void panUp();
void panDown();
}
@@ -0,0 +1,123 @@
package seng302.visualiser.cameras;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
private final Double PAN_LIMIT = 30.0;
private final Double NEAR_ZOOM_LIMIT = -30.0;
private final Double FAR_ZOOM_LIMIT = -130.0;
private final Double ZOOM_STEP = 2.5;
private ObservableList<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public TopDownCamera() {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = 0.0;
verticalPan = 0.0;
}
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays
.asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
o.addListener((obs, oldVal, newVal) -> updateCamera());
}
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX() + horizontalPan,
playerBoat.getLayoutY() + verticalPan, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= -PAN_LIMIT && horizontalPan + adjustment <= PAN_LIMIT) {
horizontalPan += adjustment;
updateCamera();
}
}
@Override
public void zoomIn() {
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP);
}
@Override
public void panLeft() {
adjustHorizontalPan(-1.0);
}
@Override
public void panRight() {
adjustHorizontalPan(1.0);
}
@Override
public void panUp() {
adjustVerticalPan(-1.0);
}
@Override
public void panDown() {
adjustVerticalPan(1.0);
}
}
@@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable {
public void switchToStartScreenView() { public void switchToStartScreenView() {
Sounds.playButtonClick(); Sounds.playButtonClick();
//TODO merge fix
setContentPane("/views/StartScreenView.fxml"); setContentPane("/views/StartScreenView.fxml");
} }
@@ -20,6 +20,8 @@ import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.SubScene; import javafx.scene.SubScene;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
@@ -46,11 +48,15 @@ import javafx.scene.shape.Polyline;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import javax.swing.ImageIcon;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.ClientYacht.PowerUpListener;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView3D; import seng302.visualiser.GameView3D;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController; import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
@@ -60,6 +66,8 @@ import seng302.visualiser.controllers.dialogs.FinishDialogController;
import seng302.visualiser.fxObjects.ChatHistory; import seng302.visualiser.fxObjects.ChatHistory;
import seng302.visualiser.fxObjects.assets_2D.WindArrow; import seng302.visualiser.fxObjects.assets_2D.WindArrow;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.fxObjects.assets_3D.ModelType;
/** /**
* Controller class that manages the display of a race * Controller class that manages the display of a race
@@ -67,6 +75,8 @@ import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class RaceViewController extends Thread implements ImportantAnnotationDelegate { public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
private final int CHAT_LIMIT = 128; private final int CHAT_LIMIT = 128;
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
private static final Integer ICON_BLINK_PERIOD = 500;
@FXML @FXML
private Pane basePane; private Pane basePane;
@@ -110,6 +120,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Label windSpeedLabel; private Label windSpeedLabel;
@FXML @FXML
private Label positionLabel, boatSpeedLabel, boatHeadingLabel; private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
//Race Data //Race Data
private Map<Integer, ClientYacht> participants; private Map<Integer, ClientYacht> participants;
@@ -130,6 +142,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private JFXDialog finishScreenDialog; private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController; private FinishDialogController finishDialogController;
//Icon stuff
private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay;
public void initialize() { public void initialize() {
Sounds.stopMusic(); Sounds.stopMusic();
Sounds.playRaceMusic(); Sounds.playRaceMusic();
@@ -222,6 +238,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
} }
public void loadRace ( public void loadRace (
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState, Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
ClientYacht player) { ClientYacht player) {
@@ -241,6 +258,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
}); });
player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions()); updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D(); gameView = new GameView3D();
// gameView.setFrameRateFXText(fpsDisplay); // gameView.setFrameRateFXText(fpsDisplay);
@@ -279,6 +299,68 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
} }
/**
* Displays the relevant icon, starts blinking it when it is close to turning off and then
* switches it off after the tokens time out
*
* @param yacht The yacht only for which we are displaying the icon
* @param tokenType The type of token, indicating what icon needs to be displayed
*/
private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) {
if (yacht == player) {
if (iconToDisplay != null) {
iconToDisplay.setVisible(false);
}
switch (tokenType) {
case BOOST:
iconToDisplay = velocityIcon;
break;
case HANDLING:
iconToDisplay = handlingIcon;
break;
case WIND_WALKER:
iconToDisplay = windWalkerIcon;
break;
case BUMPER:
iconToDisplay = bumperIcon;
break;
case RANDOM:
iconToDisplay = badRandomIcon;
break;
default:
iconToDisplay = velocityIcon;
}
//Turn icon on
iconToDisplay.setVisible(true);
//Start blinking icon towards end
if (blinkingTimer != null) {
blinkingTimer.cancel();
}
blinkingTimer = new Timer("Blinking Timer");
blinkingTimer.schedule(new TimerTask() {
Boolean isVisible = true;
@Override
public void run() {
isVisible = !isVisible;
iconToDisplay.setVisible(isVisible);
}
}, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD);
}
}
public void removeIcon(ClientYacht yacht) {
if (yacht == player) {
blinkingTimer.cancel();
iconToDisplay.setVisible(false);
iconToDisplay = null;
}
}
/** /**
* The important annotations have been changed, update this view * The important annotations have been changed, update this view
* *
@@ -7,6 +7,7 @@ import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@@ -27,6 +28,7 @@ import seng302.utilities.Sounds;
import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListener;
import seng302.visualiser.ServerListenerDelegate; import seng302.visualiser.ServerListenerDelegate;
import seng302.visualiser.controllers.cells.ServerCell; import seng302.visualiser.controllers.cells.ServerCell;
import seng302.visualiser.controllers.dialogs.ServerCreationController;
import seng302.visualiser.validators.HostNameFieldValidator; import seng302.visualiser.validators.HostNameFieldValidator;
import seng302.visualiser.validators.NumberRangeValidator; import seng302.visualiser.validators.NumberRangeValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -55,6 +57,14 @@ public class ServerListController implements Initializable, ServerListenerDelega
private Label noServersFound; private Label noServersFound;
private Logger logger = LoggerFactory.getLogger(ServerListController.class); private Logger logger = LoggerFactory.getLogger(ServerListController.class);
private JFXDialog serverCreationDialog;
private List<ServerCreationDialogListener> serverCreationDialogListeners = new ArrayList<>();
@FunctionalInterface
public interface ServerCreationDialogListener {
void notifyClosure();
}
// TODO: 12/09/17 ajm412: break this method down, its way too long. // TODO: 12/09/17 ajm412: break this method down, its way too long.
@Override @Override
@@ -115,6 +125,8 @@ public class ServerListController implements Initializable, ServerListenerDelega
serverListHostButton.setOnAction(action -> { serverListHostButton.setOnAction(action -> {
showServerCreationDialog(); showServerCreationDialog();
}); });
addServerCreationDialogListener(this::closeServerCreationDialog);
} }
/** /**
@@ -125,9 +137,11 @@ public class ServerListController implements Initializable, ServerListenerDelega
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
"/views/dialogs/ServerCreationDialog.fxml")); "/views/dialogs/ServerCreationDialog.fxml"));
try { try {
JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), serverCreationDialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
DialogTransition.CENTER); DialogTransition.CENTER);
dialog.show(); ServerCreationController serverCreationController = dialogContent.getController();
serverCreationController.setListener(serverCreationDialogListeners);
serverCreationDialog.show();
Sounds.playButtonClick(); Sounds.playButtonClick();
} catch (IOException e) { } catch (IOException e) {
logger.warn("Could not create Server Creation Dialog."); logger.warn("Could not create Server Creation Dialog.");
@@ -135,6 +149,10 @@ public class ServerListController implements Initializable, ServerListenerDelega
}); });
} }
private void closeServerCreationDialog() {
serverCreationDialog.close();
}
/** /**
* Validates the connection and attempts to connect to a given hostname and port number. * Validates the connection and attempts to connect to a given hostname and port number.
*/ */
@@ -203,4 +221,14 @@ public class ServerListController implements Initializable, ServerListenerDelega
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) { public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
Platform.runLater(() -> refreshServers(servers)); Platform.runLater(() -> refreshServers(servers));
} }
private void addServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.add(serverCreationDialogListener);
}
private void removeServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.remove(serverCreationDialogListener);
}
} }
@@ -28,6 +28,7 @@ import seng302.utilities.BonjourInstallChecker;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameClient; import seng302.visualiser.GameClient;
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
public class ViewManager { public class ViewManager {
@@ -101,8 +102,6 @@ public class ViewManager {
gameClient.stopGame(); gameClient.stopGame();
System.exit(0); System.exit(0);
}); });
jfxSnackbar = new JFXSnackbar(decorator);
} }
/** /**
@@ -187,6 +186,7 @@ public class ViewManager {
} }
}); });
jfxSnackbar = new JFXSnackbar(decorator);
} }
/** /**
@@ -220,6 +220,7 @@ public class ViewManager {
.getController(); .getController();
keyBindingDialogController.setGameClient(this.gameClient); keyBindingDialogController.setGameClient(this.gameClient);
keyBindingDialog.show(); keyBindingDialog.show();
decorator.requestFocus();
Sounds.playButtonClick(); Sounds.playButtonClick();
} }
} }
@@ -229,6 +230,26 @@ public class ViewManager {
keyBindingDialog.close(); keyBindingDialog.close();
} }
public PopupDialogController showPopupDialog() {
FXMLLoader dialogContent = new FXMLLoader(
getClass().getResource("/views/dialogs/PopupDialog.fxml"));
for (Node node : decorator.getChildren()) {
if (node instanceof StackPane) {
try {
JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(),
DialogTransition.CENTER);
PopupDialogController popupDialogController = dialogContent.getController();
popupDialogController.setPopupDialog(dialog);
dialog.show();
return popupDialogController;
} catch (IOException e) {
logger.error("Cannot load Popup dialog");
}
}
}
return null;
}
/** /**
* Show a snackbar at the bottom of the app for 1 second. * Show a snackbar at the bottom of the app for 1 second.
* *
@@ -48,6 +48,16 @@ public class KeyBindingDialogController implements Initializable {
private Label downwindLabel; private Label downwindLabel;
@FXML @FXML
private JFXToggleButton turningToggle; private JFXToggleButton turningToggle;
@FXML
private JFXButton viewButton;
@FXML
private JFXButton rightButton;
@FXML
private JFXButton leftButton;
@FXML
private JFXButton forwardButton;
@FXML
private JFXButton backwardButton;
//---------FXML END---------// //---------FXML END---------//
private GameKeyBind gameKeyBind; private GameKeyBind gameKeyBind;
@@ -60,7 +70,8 @@ public class KeyBindingDialogController implements Initializable {
gameKeyBind = GameKeyBind.getInstance(); gameKeyBind = GameKeyBind.getInstance();
buttons = new ArrayList<>(); buttons = new ArrayList<>();
Collections.addAll(buttons, Collections.addAll(buttons,
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn); zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
viewButton, rightButton, leftButton, forwardButton, backwardButton);
bindButtonWithAction(); bindButtonWithAction();
loadKeyBind(); loadKeyBind();
@@ -76,12 +87,10 @@ public class KeyBindingDialogController implements Initializable {
resetBtn.setOnMouseClicked(event -> { resetBtn.setOnMouseClicked(event -> {
gameKeyBind.setToDefault(); gameKeyBind.setToDefault();
loadKeyBind(); loadKeyBind();
showSnackBar("All keys reset!", false);
}); });
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
keyBindingDialogHeader.setFocusTraversable(true);
keyBindingDialogHeader.requestFocus();
} }
/** /**
@@ -106,7 +115,7 @@ public class KeyBindingDialogController implements Initializable {
*/ */
private void bindButtonWithAction() { private void bindButtonWithAction() {
buttonActionMap = new HashMap<>(); buttonActionMap = new HashMap<>();
for (int i = 0; i < 7; i++) { for (int i = 0; i < 12; i++) {
buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1));
} }
} }
@@ -149,6 +158,7 @@ public class KeyBindingDialogController implements Initializable {
+ "-fx-background-color: -fx-pp-front-color; " + "-fx-background-color: -fx-pp-front-color; "
+ "-fx-text-fill: -fx-pp-theme-color; " + "-fx-text-fill: -fx-pp-theme-color; "
+ "-fx-font-size: 13;"); + "-fx-font-size: 13;");
keyBindingDialogHeader.requestFocus();
} }
/** /**
@@ -0,0 +1,56 @@
package seng302.visualiser.controllers.dialogs;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
public class PopupDialogController implements Initializable {
@FXML
private Label headerLabel;
@FXML
private Label contentLabel;
@FXML
private Label closeLabel;
@FXML
private JFXButton optionButton;
@FXML
private JFXDialog popupDialog;
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public void setContent(String content) {
this.contentLabel.setText(content);
}
public void setHeader(String header) {
this.headerLabel.setText(header);
}
public void setOptionButton(JFXButton jfxButton) {
this.optionButton = jfxButton;
}
public void setOptionButtonText(String text) {
this.optionButton.setText(text);
}
public void setOptionButtonEventHandler(EventHandler<? super MouseEvent> eventHandler) {
this.optionButton.setOnMouseClicked(eventHandler);
}
public void setPopupDialog(JFXDialog popupDialog) {
this.popupDialog = popupDialog;
this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close());
}
}
@@ -5,14 +5,15 @@ import com.jfoenix.controls.JFXSlider;
import com.jfoenix.controls.JFXTextField; import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import seng302.gameServer.ServerDescription; import seng302.gameServer.ServerDescription;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.controllers.ServerListController.ServerCreationDialogListener;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.validators.FieldLengthValidator; import seng302.visualiser.validators.FieldLengthValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -28,8 +29,12 @@ public class ServerCreationController implements Initializable {
private Label maxPlayersLabel; private Label maxPlayersLabel;
@FXML @FXML
private JFXButton submitBtn; private JFXButton submitBtn;
@FXML
private Label closeLabel;
//---------FXML END---------// //---------FXML END---------//
private List<ServerCreationDialogListener> serverCreationDialogListeners;
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
updateMaxPlayerLabel(); updateMaxPlayerLabel();
maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> { maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
@@ -49,6 +54,7 @@ public class ServerCreationController implements Initializable {
validateServerSettings(); validateServerSettings();
}); });
closeLabel.setOnMouseClicked(event -> notifyListeners());
} }
/** /**
@@ -87,4 +93,14 @@ public class ServerCreationController implements Initializable {
Sounds.playHoverSound(); Sounds.playHoverSound();
} }
public void setListener(List<ServerCreationDialogListener> serverCreationDialogListeners) {
this.serverCreationDialogListeners = serverCreationDialogListeners;
}
public void notifyListeners() {
for (ServerCreationDialogListener serverCreationDialogListener : serverCreationDialogListeners) {
serverCreationDialogListener.notifyClosure();
}
}
} }
@@ -3,6 +3,7 @@ package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -30,12 +31,15 @@ public class BoatObject extends Group {
private Boolean isSelected = false; private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
private ReadOnlyDoubleWrapper rotationProperty;
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>(); private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
*/ */
public BoatObject(BoatMeshType boatMeshType) { public BoatObject(BoatMeshType boatMeshType) {
rotationProperty = new ReadOnlyDoubleWrapper(0.0);
boatAssets = ModelFactory.boatGameView(boatMeshType, colour); boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
boatAssets.hideSail(); boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll( boatAssets.getAssets().getTransforms().addAll(
@@ -83,6 +87,7 @@ public class BoatObject extends Group {
private void rotateTo(double heading, boolean sailsIn, double windDir) { private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotationProperty.set(heading);
rotation.setAngle(heading); rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1))); wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) { if (sailsIn) {
@@ -130,4 +135,8 @@ public class BoatObject extends Group {
public void addSelectedBoatListener(SelectedBoatListener sbl) { public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl); selectedBoatListenerListeners.add(sbl);
} }
public ReadOnlyDoubleWrapper getRotationProperty() {
return rotationProperty;
}
} }
@@ -156,7 +156,11 @@ public class ModelFactory {
} }
switch (tokenType) { switch (tokenType) {
case VELOCITY_PICKUP: case VELOCITY_PICKUP:
return makeCoinPickup(assets); case BUMPER_PICKUP:
case RANDOM_PICKUP:
case HANDLING_PICKUP:
case WIND_WALKER_PICKUP:
return makeTokenPickup(assets);
case FINISH_MARKER: case FINISH_MARKER:
case PLAIN_MARKER: case PLAIN_MARKER:
case START_MARKER: case START_MARKER:
@@ -185,24 +189,22 @@ public class ModelFactory {
} }
} }
private static Model makeCoinPickup(Group assets){ private static Model makeTokenPickup(Group assets) {
assets.setRotationAxis(new Point3D(1,0,0)); Rotate animationRotate = new Rotate(0, new Point3D(0, 0, 1));
assets.setRotate(90);
assets.setTranslateX(0.2);
assets.setTranslateY(1);
assets.getTransforms().addAll( assets.getTransforms().addAll(
new Translate(0,-1,0), animationRotate,
new Rotate(0 ,new Point3D(1,1,1)) new Translate(0, 0, -1)
); );
return new Model(new Group(assets), new AnimationTimer() { return new Model(new Group(assets), new AnimationTimer() {
private double rotation = 0; private double rotation = 0;
private Group group = assets; private Rotate rotate = animationRotate;
@Override @Override
public void handle(long now) { public void handle(long now) {
rotation += 1; rotation += 1;
((Rotate) group.getTransforms().get(1)).setAngle(rotation); rotate.setAngle(rotation);
} }
}); });
} }
@@ -7,6 +7,10 @@ package seng302.visualiser.fxObjects.assets_3D;
public enum ModelType { public enum ModelType {
VELOCITY_PICKUP("velocity_pickup.dae"), VELOCITY_PICKUP("velocity_pickup.dae"),
HANDLING_PICKUP("turning_pickup.dae"),
WIND_WALKER_PICKUP("wind_walker_pickup.dae"),
BUMPER_PICKUP("bumper_pickup.dae"),
RANDOM_PICKUP("random_pickup.dae"),
FINISH_MARKER ("finish_marker.dae"), FINISH_MARKER ("finish_marker.dae"),
START_MARKER ("start_marker.dae"), START_MARKER ("start_marker.dae"),
PLAIN_MARKER ("plain_marker.dae"), PLAIN_MARKER ("plain_marker.dae"),
+5
View File
@@ -51,6 +51,11 @@
/********* customised scroll bar for scroll pane ***********/ /********* customised scroll bar for scroll pane ***********/
.scroll-pane {
-fx-focus-traversable: false;
-fx-border-style: none;
}
/* The main scrollbar **track** CSS class */ /* The main scrollbar **track** CSS class */
.scroll-bar:horizontal .track, .scroll-bar:horizontal .track,
.scroll-bar:vertical .track { .scroll-bar:vertical .track {
@@ -9,8 +9,13 @@
} }
#closeLabel:hover { #closeLabel:hover {
-fx-text-fill: -fx-pp-theme-color; -fx-text-fill: red;
-fx-font-size: 33; -fx-font-size: 33px;
}
.sectionLabel {
-fx-text-fill: -fx-pp-dark-text-color;
-fx-font-size: 20px;
} }
JFXButton { JFXButton {
+33
View File
@@ -0,0 +1,33 @@
#headerLabel {
-fx-font-size: 20px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-font-size: 24px;
-fx-text-fill: red;
}
#contentLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#optionButton {
-fx-background-color: -fx-pp-theme-color;
-fx-text-fill: -fx-pp-light-text-color;
-fx-font-size: 18px;
-fx-effect: -fx-pp-dropshadow-light;
-fx-max-height: 55;
-fx-focus-traversable: false;
}
#optionButton:hover {
-fx-font-size: 20px !important;
-fx-background-color: -fx-pp-light-theme-color;
}
@@ -45,3 +45,13 @@
.maxPlayers { .maxPlayers {
-fx-font-size: 13px; -fx-font-size: 13px;
} }
#closeLabel {
-fx-font-size: 30;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-text-fill: red;
-fx-font-size: 33px;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+147
View File
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:47:50</created>
<modified>2017-09-19T15:47:50</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0 0 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 6.87021e-4 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616991 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.1875942 0.5773453 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
+332
View File
@@ -0,0 +1,332 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:54:38</created>
<modified>2017-09-19T15:54:38</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.8 0.6035923 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.8 0.1522076 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.01023849 0.004662884 0.64 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0 0.2456551 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_003-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">8.07677e-5 0.64 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_004-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0 0.005309466 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_005-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0 0 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
<material id="Material_001-material" name="Material_001">
<instance_effect url="#Material_001-effect"/>
</material>
<material id="Material_002-material" name="Material_002">
<instance_effect url="#Material_002-effect"/>
</material>
<material id="Material_003-material" name="Material_003">
<instance_effect url="#Material_003-effect"/>
</material>
<material id="Material_004-material" name="Material_004">
<instance_effect url="#Material_004-effect"/>
</material>
<material id="Material_005-material" name="Material_005">
<instance_effect url="#Material_005-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5350354 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8183268 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8183217 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.570192 0.7464457 -0.3430743 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.6991799 0.2635454 0.6645987 0.05184978 0.746441 0.6634285 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.185151 0.569826 0.8006358 -0.4685443 0.5765037 0.6694099 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.009833872 0.9466192 0.3222044 -0.2904988 0.9398801 0.1795436 -0.5345759 0.7778646 0.3303867 -0.9071158 0.2635452 0.3281539 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7989099 0.5698285 -0.1924537 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.2925817 0.9466192 -0.1353079 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.8082743 0.5765079 0.1197141 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="15">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>36 12 36 9 12 37 41 12 38 35 14 42 8 14 43 40 14 44 34 16 48 7 16 49 39 16 50 33 18 54 6 18 55 37 18 56 32 20 60 10 20 61 38 20 62 30 23 69 9 23 70 36 23 71 28 26 78 8 26 79 35 26 80 26 29 87 7 29 88 34 29 89 24 32 96 6 32 97 33 32 98 22 35 105 10 35 106 32 35 107 16 47 141 19 47 142 21 47 143 19 50 150 17 50 151 20 50 152 17 53 159 12 53 160 18 53 161 15 56 168 13 56 169 16 56 170 12 58 174 13 58 175 14 58 176</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
<polylist material="Material_001-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>23 22 66 30 22 67 36 22 68 31 25 75 28 25 76 35 25 77 29 28 84 26 28 85 34 28 86 27 31 93 24 31 94 33 31 95 25 34 102 22 34 103 32 34 104 30 36 108 21 36 109 31 36 110 28 38 114 20 38 115 29 38 116 26 40 120 18 40 121 27 40 122 24 42 126 14 42 127 25 42 128 22 44 132 15 44 133 23 44 134</p>
</polylist>
<polylist material="Material_002-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 23 21 63 36 21 64 10 21 65 31 24 72 35 24 73 9 24 74 29 27 81 34 27 82 8 27 83 27 30 90 33 30 91 7 30 92 25 33 99 32 33 100 6 33 101</p>
</polylist>
<polylist material="Material_003-material" count="5">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 </vcount>
<p>38 11 33 36 11 34 41 11 35 41 13 39 35 13 40 40 13 41 40 15 45 34 15 46 39 15 47 39 17 51 33 17 52 37 17 53 37 19 57 32 19 58 38 19 59</p>
</polylist>
<polylist material="Material_004-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 16 46 138 21 46 139 5 46 140 19 49 147 20 49 148 4 49 149 17 52 156 18 52 157 3 52 158 12 57 171 14 57 172 2 57 173</p>
</polylist>
<polylist material="Material_005-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>21 37 111 4 37 112 31 37 113 20 39 117 3 39 118 29 39 119 18 41 123 2 41 124 27 41 125 14 43 129 1 43 130 25 43 131 15 45 135 5 45 136 23 45 137 19 48 144 4 48 145 21 48 146 17 51 153 3 51 154 20 51 155 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 13 59 177 1 59 178 14 59 179</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
<instance_material symbol="Material_001-material" target="#Material_001-material"/>
<instance_material symbol="Material_002-material" target="#Material_002-material"/>
<instance_material symbol="Material_003-material" target="#Material_003-material"/>
<instance_material symbol="Material_004-material" target="#Material_004-material"/>
<instance_material symbol="Material_005-material" target="#Material_005-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-26T19:13:35</created>
<modified>2017-09-26T19:13:35</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.01630632 0.52949 0.0134405 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0.5334254 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284252 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616992 0.7240421 0.1947362 0.6616954 0.4911194 0.356821 0.7946576 0.4089462 0.6284253 0.6616984 -0.1875943 0.5773454 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875943 -0.5773454 0.7946577 0.03853034 -0.7487788 0.6616992 0.4911193 -0.356821 0.7946577 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875943 0.5773454 -0.7946577 -0.0385304 0.7487789 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911193 0.356821 -0.7946577 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911194 -0.356821 -0.7946576 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487789 -0.6616991 0.1875943 -0.5773454 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150898 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150899 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:46:34</created>
<modified>2017-09-19T15:46:34</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.03920602 0.04758029 0.8 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0.5287738 0.5454956 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616991 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.1875942 0.5773453 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
+102 -48
View File
@@ -1,5 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.lang.String?> <?import java.lang.String?>
@@ -7,17 +16,16 @@
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?> <?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308" <StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
prefHeight="800.0" prefWidth="1200.0" prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8.0.111"
style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.RaceViewController"> fx:controller="seng302.visualiser.controllers.RaceViewController">
<children> <children>
@@ -38,17 +46,15 @@
valignment="BOTTOM" vgrow="SOMETIMES"/> valignment="BOTTOM" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" <GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer">
styleClass="timer">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
prefWidth="50.0"/> prefWidth="50.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0"
minWidth="135.0" prefWidth="135.0"/> prefWidth="135.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
@@ -80,25 +86,20 @@
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="2"> <GridPane GridPane.columnIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
prefWidth="100.0"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
</GridPane> </GridPane>
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" <GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2">
GridPane.rowIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0"
minWidth="390.0" prefWidth="390.0"/> prefWidth="390.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
@@ -121,22 +122,21 @@
minWidth="90.0" prefWidth="90.0"/> minWidth="90.0" prefWidth="90.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0" <RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0"
prefHeight="50.0" valignment="CENTER" vgrow="SOMETIMES"/> valignment="CENTER" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<JFXButton fx:id="chatSend" alignment="CENTER" <JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED"
buttonType="RAISED" maxHeight="-Infinity" focusTraversable="false" maxHeight="-Infinity"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="35.0" text="SEND" minWidth="-Infinity" prefHeight="35.0" text="SEND"
GridPane.columnIndex="1"> GridPane.columnIndex="1">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
top="10.0"/>
</GridPane.margin> </GridPane.margin>
</JFXButton> </JFXButton>
<JFXTextField fx:id="chatInput" maxHeight="35.0" <JFXTextField fx:id="chatInput" focusTraversable="false"
minHeight="-Infinity" prefHeight="35.0"> maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="20.0" right="10.0"/> <Insets bottom="10.0" left="20.0" right="10.0"/>
</GridPane.margin> </GridPane.margin>
@@ -158,29 +158,27 @@
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER" prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="BOTTOM"> GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0"
minWidth="110.0" prefWidth="110.0"/> prefWidth="110.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
minWidth="10.0"
prefWidth="132.0"/> prefWidth="132.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="positionLabel" text="Position:" <Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP">
GridPane.rowSpan="2" GridPane.valignment="TOP">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
</Label> </Label>
<Label fx:id="boatSpeedLabel" text="Boat Speed:" <Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.rowSpan="2" GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
</opaqueInsets> </opaqueInsets>
@@ -189,8 +187,8 @@
</padding> </padding>
</Label> </Label>
<Label fx:id="boatHeadingLabel" text="Boat Heading:" <Label fx:id="boatHeadingLabel" text="Boat Heading:"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.rowSpan="2" GridPane.valignment="BOTTOM"> GridPane.valignment="BOTTOM">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
@@ -203,12 +201,12 @@
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/> prefHeight="120.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
prefHeight="30.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<ImageView fx:id="windImageView" fitHeight="92.0" <ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0"
fitWidth="109.0" pickOnBounds="true" preserveRatio="true" pickOnBounds="true" preserveRatio="true"
GridPane.halignment="CENTER" GridPane.rowSpan="2" GridPane.halignment="CENTER" GridPane.rowSpan="2"
GridPane.valignment="CENTER"/> GridPane.valignment="CENTER"/>
<Label fx:id="windSpeedLabel" text="0.0 Knots" <Label fx:id="windSpeedLabel" text="0.0 Knots"
@@ -235,6 +233,62 @@
<Insets bottom="10.0" left="10.0" top="40.0"/> <Insets bottom="10.0" left="10.0" top="40.0"/>
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.halignment="CENTER" GridPane.rowIndex="1">
<image>
<Image url="@../icons/velocity.png"/>
</image>
</ImageView>
<ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/handlingIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="2" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/windWalkerIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="3" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/bumperIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="4" GridPane.halignment="CENTER"
GridPane.rowIndex="1" GridPane.valignment="CENTER">
<image>
<Image url="@../icons/ayy_lmao.gif"/>
</image>
</ImageView>
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
</children> </children>
@@ -6,117 +6,226 @@
<?import java.net.URL?> <?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity" <JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController"> fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController">
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
<children> <children>
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="70.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBIND" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER" /> <ScrollPane prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
<Label text="ZOOM IN" GridPane.halignment="CENTER" GridPane.rowIndex="1" <content>
GridPane.valignment="CENTER"> <StackPane prefHeight="150.0" prefWidth="200.0">
<GridPane.margin> <children>
<Insets/> <GridPane>
</GridPane.margin></Label> <children>
<Label text="ZOOM OUT" GridPane.halignment="CENTER" GridPane.rowIndex="2" <JFXButton fx:id="viewButton" buttonType="RAISED"
GridPane.valignment="CENTER"> minHeight="35.0" prefWidth="120.0" text="F1"
<GridPane.margin> GridPane.columnIndex="1" GridPane.halignment="CENTER"
<Insets/> GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
</GridPane.margin></Label> <Label text="VIEW ASPECT" GridPane.halignment="CENTER"
<Label text="VMG" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
GridPane.valignment="CENTER"> <JFXButton fx:id="rightButton" buttonType="RAISED"
<GridPane.margin> minHeight="35.0" prefWidth="120.0" text="D"
<Insets/> GridPane.columnIndex="1" GridPane.halignment="CENTER"
</GridPane.margin></Label> GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<Label text="SAILS IN/OUT" GridPane.halignment="CENTER" GridPane.rowIndex="4" <Label text="RIGHT" GridPane.halignment="CENTER"
GridPane.valignment="CENTER"> GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<GridPane.margin> <JFXButton fx:id="leftButton" buttonType="RAISED"
<Insets/> minHeight="35.0" prefWidth="120.0" text="A"
</GridPane.margin></Label> GridPane.columnIndex="1" GridPane.halignment="CENTER"
<Label text="TACK/GYBE" GridPane.halignment="CENTER" GridPane.rowIndex="5" GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
GridPane.valignment="CENTER"> <Label text="LEFT" GridPane.halignment="CENTER"
<GridPane.margin> GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
<Insets/> <JFXButton fx:id="forwardButton" buttonType="RAISED"
</GridPane.margin></Label> minHeight="35.0" prefWidth="120.0" text="W"
<Label fx:id="upwindLabel" text="UPWIND" GridPane.halignment="CENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER"> GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
<GridPane.margin> <Label text="FORWARD" GridPane.halignment="CENTER"
<Insets/> GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
</GridPane.margin></Label> <JFXButton fx:id="backwardButton" buttonType="RAISED"
<Label fx:id="downwindLabel" text="DOWNWIND" GridPane.halignment="CENTER" minHeight="35.0" prefWidth="120.0" text="S"
GridPane.rowIndex="7" GridPane.valignment="CENTER"> GridPane.columnIndex="1" GridPane.halignment="CENTER"
<GridPane.margin> GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
<Insets/> <Label text="BACKWARD" GridPane.halignment="CENTER"
</GridPane.margin></Label> GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED" maxHeight="-Infinity" <Label text="ZOOM IN" GridPane.halignment="CENTER"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="Z" GridPane.rowIndex="1" GridPane.valignment="CENTER">
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" <GridPane.margin>
GridPane.valignment="CENTER"/> <Insets/>
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED" maxHeight="-Infinity" </GridPane.margin>
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="X" </Label>
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" <Label text="ZOOM OUT" GridPane.halignment="CENTER"
GridPane.valignment="CENTER"/> GridPane.rowIndex="2" GridPane.valignment="CENTER">
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED" maxHeight="-Infinity" <GridPane.margin>
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" <Insets/>
text="SPACE" GridPane.columnIndex="1" GridPane.halignment="CENTER" </GridPane.margin>
GridPane.rowIndex="3" GridPane.valignment="CENTER"/> </Label>
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn" buttonType="RAISED" <Label text="VMG" GridPane.halignment="CENTER"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" GridPane.rowIndex="3" GridPane.valignment="CENTER">
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1" GridPane.halignment="CENTER" <GridPane.margin>
GridPane.rowIndex="4" GridPane.valignment="CENTER"/> <Insets/>
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn" buttonType="RAISED" maxHeight="-Infinity" </GridPane.margin>
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" </Label>
text="ENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER" <Label text="SAILS IN/OUT" GridPane.halignment="CENTER"
GridPane.rowIndex="5" GridPane.valignment="CENTER"/> GridPane.rowIndex="4" GridPane.valignment="CENTER">
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED" maxHeight="-Infinity" <GridPane.margin>
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" <Insets/>
text="PAGE_UP" GridPane.columnIndex="1" GridPane.halignment="CENTER" </GridPane.margin>
GridPane.rowIndex="6" GridPane.valignment="CENTER"/> </Label>
<JFXButton id="DOWNWIND" fx:id="downwindBtn" buttonType="RAISED" maxHeight="-Infinity" <Label text="TACK/GYBE" GridPane.halignment="CENTER"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" GridPane.rowIndex="5" GridPane.valignment="CENTER">
text="PAGE_DOWN" GridPane.columnIndex="1" GridPane.halignment="CENTER" <GridPane.margin>
GridPane.rowIndex="7" GridPane.valignment="CENTER"/> <Insets/>
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity" prefHeight="35.0" </GridPane.margin>
text="OFF / ON" GridPane.columnIndex="1" GridPane.halignment="CENTER" </Label>
GridPane.rowIndex="8"/> <Label fx:id="upwindLabel" text="UPWIND"
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER" GridPane.rowIndex="8" GridPane.halignment="CENTER" GridPane.rowIndex="6"
GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<Label fx:id="downwindLabel" text="DOWNWIND"
GridPane.halignment="CENTER" GridPane.rowIndex="7"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="Z"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="1" GridPane.valignment="CENTER"/>
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="X"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="SPACE"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="CENTER"/>
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="ENTER" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="5"
GridPane.valignment="CENTER"/>
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="PAGE_UP"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
<JFXButton id="DOWNWIND" fx:id="downwindBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="PAGE_DOWN" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="7"
GridPane.valignment="CENTER"/>
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity"
prefHeight="35.0" text="OFF / ON" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="8"/>
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER"
GridPane.rowIndex="8" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
<Label styleClass="sectionLabel" text="BOAT ACTIONS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
<Label styleClass="sectionLabel" text="CAMERA SETTINGS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="250.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="150.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
</rowConstraints>
</GridPane>
</children>
</StackPane>
</content>
</ScrollPane>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBINDING" GridPane.columnSpan="2"
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity" <JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER"/> GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" translateY="-5.0" GridPane.columnIndex="1"
GridPane.halignment="RIGHT" GridPane.valignment="TOP"/>
</children> </children>
</GridPane> </GridPane>
</children> </children>
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css" />
<URL value="@../../css/Master.css" />
</stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.PopupDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
prefHeight="80.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
prefWidth="150.0" GridPane.halignment="RIGHT" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</JFXButton>
<Label fx:id="contentLabel" text="Popup content goes here ..."
GridPane.rowIndex="1"/>
<Label fx:id="headerLabel" text="Popup header"/>
<Label fx:id="closeLabel" text="✖" translateY="-10.0" GridPane.halignment="RIGHT"/>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/Popup.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
</JFXDialogLayout>
@@ -4,14 +4,18 @@
<?import com.jfoenix.controls.JFXDialogLayout?> <?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXSlider?> <?import com.jfoenix.controls.JFXSlider?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.lang.String?> <?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8.0.111"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
<children> <children>
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
@@ -59,11 +63,13 @@
</VBox> </VBox>
</children> </children>
</GridPane> </GridPane>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
</children> </children>
</GridPane> </GridPane>
</children> </children>
<stylesheets> <stylesheets>
<String fx:value="/css/dialogs/ServerCreation.css" /> <URL value="@../../css/dialogs/ServerCreation.css"/>
<String fx:value="/css/Master.css"/> <URL value="@../../css/Master.css"/>
</stylesheets> </stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -110,7 +110,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(5.0, GameState.getSpeedMultiplier(), 0.00001); Assert.assertEquals(5.0, GameState.getServerSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
try { try {
Thread.sleep(200); Thread.sleep(200);
@@ -150,7 +150,7 @@ public class ChatCommandsTest {
ie.printStackTrace(); ie.printStackTrace();
} }
mst.terminate(); mst.terminate();
Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001);
try { try {
Thread.sleep(2000); Thread.sleep(2000);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
@@ -194,7 +194,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
host.setSocketToClose(); host.setSocketToClose();
client.setSocketToClose(); client.setSocketToClose();
@@ -0,0 +1,50 @@
package seng302.utilities;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.token.Token;
/**
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawnTest {
private RandomSpawn randomSpawn;
Mark mark1 = new Mark("mark1", 0, 57.670333, 11.827833, 0);
Mark mark2 = new Mark("mark2", 1, 57.671829, 11.842049, 1);
CompoundMark compoundMark1 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark1)));
CompoundMark compoundMark2 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark2)));
List<CompoundMark> markOrder = new ArrayList<>(Arrays.asList(compoundMark1, compoundMark2));
@Before
public void setup() {
randomSpawn = new RandomSpawn(markOrder);
}
@Test
public void testGetRandomTokenLocation() {
GeoPoint testMidPoint = GeoUtility
.getDirtyMidPoint(compoundMark1.getMidPoint(), compoundMark2.getMidPoint());
Double maxDistance = GeoUtility.getDistance(testMidPoint, compoundMark2.getMidPoint());
for (int i = 0; i < 1000; i++) {
Token token = randomSpawn.getRandomTokenLocation();
Double distanceFromCentreRadius = GeoUtility.getDistance(testMidPoint, token);
assertTrue("Out of bounds token", distanceFromCentreRadius <= maxDistance);
}
}
}