101 Commits

Author SHA1 Message Date
Cedric Beck
4430b37581 fixed wrong dice rotation because of fps drop 2024-12-07 17:00:42 +01:00
Cedric Beck
e14b8cb510 added converted assets 2024-12-07 16:50:43 +01:00
Cedric Beck
6d3c733f91 added effect for shell flying 2024-12-07 14:45:39 +01:00
Cedric Beck
1a079dad44 added shell asset for ShellAnimation 2024-12-07 14:22:36 +01:00
Cedric Beck
32f49a6181 added shellAnimation without shell asset 2024-12-07 13:30:30 +01:00
Cedric Beck
29c6b13300 added MatrixAnimation 2024-12-06 17:09:06 +01:00
Cedric Beck
2ac2de645b working on matrix-animation 2024-12-06 14:56:04 +01:00
Cedric Beck
f3816cb2a5 added particle_cir.png 2024-12-05 17:49:56 +01:00
Cedric Beck
997c4c589e removed setOwnColor 2024-12-05 17:23:15 +01:00
Cedric Beck
d14a0aef86 fixed ownColor sync problem 2024-12-05 17:22:37 +01:00
Felix Koppe
ac5d7ed74b Add sounds 2024-12-05 17:11:07 +01:00
Felix Koppe
4a7c23708c Add jetAnimation 2024-12-05 16:21:13 +01:00
Felix Koppe
0e6a2499b7 Fix fullscreen issue 2024-12-04 18:38:35 +01:00
Felix Koppe
00d86c5c10 Improve ceremonyView 2024-12-04 15:33:34 +01:00
Felix Koppe
990e476753 Add Q/E rotation 2024-12-04 15:27:33 +01:00
Felix Koppe
71fc08a05c Add interrupt 2024-12-04 15:11:31 +01:00
Cedric Beck
9e1ca584c7 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-04 13:56:08 +01:00
Cedric Beck
9199fbffd8 removed tests, fixed null exception in CardLayer 2024-12-04 13:56:03 +01:00
Felix Koppe
6f7c5346d2 Merge commit 2024-12-04 13:34:14 +01:00
Felix Koppe
ef1ce63db6 Try to make server stop on leave 2024-12-04 13:33:39 +01:00
Cedric Beck
44ef21e6af added handCard Num to playerName display + added remove card in guiHandler 2024-12-04 11:38:35 +01:00
Felix Koppe
11d6dd4500 Improve video dialog 2024-12-04 10:00:41 +01:00
Felix Koppe
d71f824ca6 Add fullscreen option 2024-12-04 09:41:08 +01:00
Felix Koppe
8e6cb27662 Fix lobbyView ready behavior on tskChange 2024-12-04 07:53:18 +01:00
Hanno Fleischer
7053b163e5 adjusted LobbyState in the client to use the correct Data 2024-12-03 18:19:55 +01:00
Hanno Fleischer
81cb2f33ff adjusted all constuctors of nodes so that if someone creates a node the piece will be null and the option for a constuctor without arguments is still given for serialization purposes 2024-12-03 17:56:39 +01:00
Hanno Fleischer
69865bb504 added the playeringamenotification to be created from the right dataset 2024-12-03 16:48:08 +01:00
Felix Koppe
db50986f3f Fix serialisation issue 2024-12-03 15:38:13 +01:00
Felix Koppe
a0a088a0c4 Fix minor error in notification processing 2024-12-03 15:00:00 +01:00
Cedric Beck
c4d11ff961 added window title 2024-12-03 09:15:14 +01:00
Daniel Grigencha
bb51976127 Updated 'Node' class.
Updated the 'Node' class by overload the 'isOccupied' method in it.
2024-12-03 04:57:30 +01:00
Daniel Grigencha
0db1f08f3c Updated abstract 'GameAutomatonState' class.
Updated the abstract 'GameAutomatonState' class by adding the 'getGameAutomaton' method to it.
2024-12-03 04:49:16 +01:00
Daniel Grigencha
336f1ec316 Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_EYES' constant to it.
2024-12-03 04:29:16 +01:00
Daniel Grigencha
a1e687912a Updated abstract 'TurnAutomatonState' class.
Updated the abstract 'TurnAutomatonState' class by adding the 'getTurnAutomaton' method to it.
2024-12-03 04:09:35 +01:00
Daniel Grigencha
2248d044c1 Updated 'AnimationState' class.
Updated the 'AnimationState' class by updating the content inside the 'received(AnimationEndMessage msg, int from) method in it.
2024-12-03 03:41:58 +01:00
Daniel Grigencha
79bf1c16e8 Updated 'Game' class.
Updated the 'Game' class by adding the 'getActivePlayerId' method to it.
2024-12-03 03:40:24 +01:00
Daniel Grigencha
3353a890d3 Updated 'Game' class.
Updated the 'Game' class by adding the 'getPlayerIdByColor' method to it.
2024-12-03 03:36:22 +01:00
Daniel Grigencha
a012402a85 Updated abstract 'TurnAutomatonState' class.
Updated the abstract 'TurnAutomatonState' class by updating the JavaDoc text of the constructor.
2024-12-03 02:15:10 +01:00
Daniel Grigencha
5aaf8d4850 Updated 'TurnState' class.
Updated the 'TurnState' class by setting the start state in it.
2024-12-03 01:31:22 +01:00
Daniel Grigencha
35ab777f04 Updated 'DetermineStartPlayerState' class.
Updated the 'DetermineStartPlayerState' class by fixing the logic inside the received(RequestDieMessage msg, int from)' method in it.
2024-12-03 01:30:39 +01:00
Daniel Grigencha
c707abc465 Updated 'Die' class.
Updated the 'Die' class by adding another constructor for test cases to it.
2024-12-03 01:04:02 +01:00
Daniel Grigencha
2a84e7cf65 Updated 'Player' class.
Updated the 'Player' class by moving all content of 'PlayerData' class in 'Player' class.
2024-12-03 00:51:45 +01:00
Daniel Grigencha
3a02edb944 Updated 'PlayerData' class.
Updated the 'PlayerData' class by updating the 'Piece' creation inside the constructor.
2024-12-03 00:50:53 +01:00
Daniel Grigencha
1870d4fe0e Updated 'ShieldState' enumeration.
Updated the 'ShieldState' enumeration by removing unused methods from it.
2024-12-03 00:49:09 +01:00
Daniel Grigencha
5cf9746931 Updated 'PieceState' enumeration.
Updated the 'PieceState' enumeration by removing unused methods from it.
2024-12-03 00:48:39 +01:00
Daniel Grigencha
5b9bc7aa36 Updated 'Piece' class.
Updated the 'Piece' class by removing the unused 'id' parameter from the constructor.
2024-12-03 00:38:24 +01:00
Daniel Grigencha
abe66aff5d Updated 'LobbyState' class.
Updated 'LobbyState' class by removed unused imports in it.
2024-12-03 00:37:24 +01:00
Fleischer Hanno
eea566cc8b added the logic for server shutdown 2024-12-02 23:25:54 +01:00
Daniel Grigencha
bd07a44607 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 23:24:02 +01:00
Daniel Grigencha
1f64676d31 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by adding the 'shutdown' message to it.
2024-12-02 23:23:56 +01:00
Daniel Grigencha
838f59b9aa Updated 'ServerState' class.
Updated the 'ServerState' class by filling the 'received(LeaveGameMessage msg, int from)' in it.
2024-12-02 23:22:45 +01:00
Daniel Grigencha
002a42be38 Updated 'LobbyState' class.
Updated the 'LobbyState' class by removing the 'received(LeaveGameMessage msg, int from)' from it.
2024-12-02 23:21:42 +01:00
Daniel Grigencha
a1d10521ac Updated 'ServerSener' interface.
Updated the 'ServerSender' interface by adding the 'shutdown' method to it.
2024-12-02 23:14:29 +01:00
Fleischer Hanno
4e6a272e7a added that when the client is in the game state and recieves the ceremony message it always changes to ceremony state 2024-12-02 23:08:56 +01:00
Daniel Grigencha
516848a67e Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 23:06:49 +01:00
Daniel Grigencha
659d69d3eb Updated 'GameState' class.
Updated the 'GameState' class by sending a broadcast message after a player left the game and only one player is remaining.
2024-12-02 23:06:44 +01:00
Daniel Grigencha
fb6cbeaaf5 Updated 'ServerStartGameMessage' class.
Updated the 'ServerStartGameMessage' class by adding the 'board' attribute and its getter method to it.
2024-12-02 23:00:39 +01:00
Cedric Beck
25f750c8b6 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 22:58:58 +01:00
Cedric Beck
3f49b432c4 added SSAO and FXAA 2024-12-02 22:58:52 +01:00
Daniel Grigencha
252c37ae9a Updated 'LobbyState' class.
Updated the 'LobbyState' class by sending the 'ServerStartGameMessage' with a 'Board' object.
2024-12-02 22:58:46 +01:00
Fleischer Hanno
4566d4c9a8 Merge remote-tracking branch 'origin/development' into development 2024-12-02 22:46:12 +01:00
Fleischer Hanno
e9ba888651 changed the logic so that the isHost is not decided by the client and instead by the server 2024-12-02 22:45:44 +01:00
Cedric Beck
cbbb98037b Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 22:43:16 +01:00
Cedric Beck
aa651ec62f added trees 2024-12-02 22:43:03 +01:00
Daniel Grigencha
e163b87cc4 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the logic inside the 'connectionAdded' method in it.
2024-12-02 22:41:17 +01:00
Daniel Grigencha
1eb24b7a66 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the logic inside the 'connectionAdded' method in it.
2024-12-02 22:37:46 +01:00
Daniel Grigencha
492f7422f5 Updated 'LobbyAcceptMessage' class.
Updated the 'LobbyAcceptMessage' class by adding the 'host' attribute and its getter method to it.
2024-12-02 22:36:48 +01:00
Daniel Grigencha
27f8af70f5 Updated 'Game' class.
Updated the 'Game' class by setting the default value of 'host' attribute. In Addition, the 'isHost' method was added.
2024-12-02 22:34:45 +01:00
Fleischer Hanno
5910fcc701 added the client logic to receive the LobbyAccept and LobbyDeny message 2024-12-02 21:52:07 +01:00
Felix Koppe
e94ed1e019 Fix syntax error 2024-12-02 21:51:09 +01:00
Felix Koppe
7d54a906dd Add some more names 2024-12-02 21:48:23 +01:00
Felix Koppe
5ae65921bf Add more random names 2024-12-02 21:42:12 +01:00
Daniel Grigencha
468e4005dc Updated 'LobbyState' class.
Updated the 'LobbyState' class by sending a broadcast update the new ready state of the client.
2024-12-02 21:23:53 +01:00
Daniel Grigencha
72321eab9a Updated 'LobbyState' class.
Updated the 'LobbyState' class by updating all received methods in it.
2024-12-02 21:22:49 +01:00
Daniel Grigencha
951c92d890 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 21:12:03 +01:00
Felix Koppe
e87eb569c2 Add showInfo to MdgaView 2024-12-02 21:16:50 +01:00
Felix Koppe
baa967ecfc Merge commit 2024-12-02 21:12:56 +01:00
Felix Koppe
8d39d61c71 Add infoNotification 2024-12-02 21:12:43 +01:00
Daniel Grigencha
7fcee3cac0 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by register the 'IncorrectRequestMessage' class to the serializer.
2024-12-02 21:11:59 +01:00
Daniel Grigencha
06d4b322e7 Merge branch 'development' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-01 into development 2024-12-02 21:04:41 +01:00
Daniel Grigencha
1cf14f65bb Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by updating the 'connectionAdded' method in it. In Addition, the JavaDoc text for this method was addded.
2024-12-02 21:04:36 +01:00
Fleischer Hanno
ebb9f839c7 added JavaDocs in Resources.java 2024-12-02 20:58:00 +01:00
Daniel Grigencha
3eef4b2a02 Updated 'PlayerData' class.
Updated the 'PlayerData' class by replacing the magic constants with the 'Resources' class. In Addition, some JavaDoc texts were updated.
2024-12-02 20:56:59 +01:00
Daniel Grigencha
c1fa679261 Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_PIECES' constant to it.
2024-12-02 20:45:07 +01:00
Daniel Grigencha
c48f924ead Updated 'Resources' class.
Updated the 'Resources' class by adding the 'MAX_PLAYERS' constant to it.
2024-12-02 20:43:47 +01:00
Fleischer Hanno
73859d8c81 added methods for getting Boolean, String, Double and int 2024-12-02 20:34:52 +01:00
Felix Koppe
1918aa80ff Merge commit 2024-12-02 20:33:36 +01:00
Felix Koppe
d062b9dabc Add forceStartGameButton to host in lobby 2024-12-02 20:32:46 +01:00
Fleischer Hanno
7ddcdc3f48 added the first error.messages and adjusted 2024-12-02 20:24:17 +01:00
Fleischer Hanno
2cefc2c293 Merge remote-tracking branch 'origin/development' into development 2024-12-02 20:19:44 +01:00
Daniel Grigencha
c4304ae99a Updated 'Game' class.
Updated the 'Game' class by removing the 'allReady' attribute in it. In Addtion, the 'areAllReady' method was added.
2024-12-02 20:19:13 +01:00
Fleischer Hanno
005df94114 added Resources calss to access teh properties 2024-12-02 19:55:18 +01:00
Daniel Grigencha
44f893ccef Updated 'Game' class.
Updated the 'Game' class by setting the 'die' attribute correctly inside the constructor.
2024-12-02 19:45:11 +01:00
Daniel Grigencha
0d9a922f55 Removed 'PlayerDataMessage' and 'StartBriefingMessage'. 2024-12-02 19:16:01 +01:00
Daniel Grigencha
289158cf35 Updated 'MdgaServer' class.
Updated the 'MdgaServer' class by removing the 'PlayerDataMessage' and 'StartBriefingMessage' from the serializer.
2024-12-02 19:14:11 +01:00
Fleischer Hanno
0a0762b6c9 removed all instances of PlayerDataMEssage and StartBriefingMessage 2024-12-02 19:07:58 +01:00
Fleischer Hanno
90a21087df added logic for incorrectRequest message and removed messages playerdata and startbriefing and created javadocs 2024-12-02 19:02:00 +01:00
Daniel Grigencha
294ecdc56f Updated 'IncorrectRequestMessage' class.
Updated the 'IncorrectRequestMessage' class by updating the content inside the 'accept' method in it.
2024-12-02 19:00:21 +01:00
Daniel Grigencha
347ed152b8 Added 'IncorrectRequestMessage' class.
Added the 'IncorrectRequestMessage' class to this project. It will be used to send the client an incorrect request message to show they did something wrong.
2024-12-02 18:58:15 +01:00
Daniel Grigencha
3daafde9f1 Updated 'ServerInterpreter' class.
Updated the 'ServerInterpreter' class by adding the 'received(IncorrectRequestMessage msg)' method to it.
2024-12-02 18:50:42 +01:00
Daniel Grigencha
09fda6b167 Updated 'Game' class.
Updated the 'Game' class by adding the 'isColorTaken' method to it.
2024-12-02 18:18:04 +01:00
114 changed files with 3402 additions and 655 deletions

View File

@@ -1,19 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MdgaApp" type="Application" factoryName="Application" singleton="false" nameIsGenerated="true">
<option name="ALTERNATIVE_JRE_PATH" value="temurin-20" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="MAIN_CLASS_NAME" value="pp.mdga.client.MdgaApp" />
<module name="Projekte.mdga.client.main" />
<option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties -ea" />
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.mdga.client.board.outline.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -30,15 +30,20 @@ public enum Asset {
tank,
world(1.2f),
shieldRing("Models/shieldRing/shieldRing.j3o", null),
treeSmall,
treeBig,
treeSmall(1.2f),
treeBig(1.2f),
turboCard,
turboSymbol("Models/turboCard/turboSymbol.j3o", "Models/turboCard/turboCard_diff.j3o"),
turboSymbol("Models/turboCard/turboSymbol.j3o", "Models/turboCard/turboCard_diff.png"),
swapCard,
swapSymbol("Models/swapCard/swapSymbol.j3o", "Models/swapCard/swapCard_diff.j3o"),
swapSymbol("Models/swapCard/swapSymbol.j3o", "Models/swapCard/swapCard_diff.png"),
shieldCard,
shieldSymbol("Models/shieldCard/shieldSymbol.j3o", "Models/shieldCard/shieldCard_diff.j3o"),
dice
shieldSymbol("Models/shieldCard/shieldSymbol.j3o", "Models/shieldCard/shieldCard_diff.png"),
dice,
tankShoot("Models/tank/tankShoot_bot.j3o", "Models/tank/tank_diff.png"),
tankShootTop("Models/tank/tankShoot_top.j3o", "Models/tank/tank_diff.png"),
treesSmallBackground("Models/treeSmall/treesSmallBackground.j3o", "Models/treeSmall/treeSmall_diff.png", 1.2f),
treesBigBackground("Models/treeBig/treesBigBackground.j3o", "Models/treeBig/treeBig_diff.png", 1.2f),
shell
;
private final String modelPath;

View File

@@ -27,6 +27,7 @@
import pp.mdga.notification.SelectableCardsNotification;
import java.util.List;
import java.util.UUID;
public class InputSynchronizer {
@@ -39,6 +40,11 @@ public class InputSynchronizer {
private CardControl hoverCard;
private PieceControl hoverPiece;
private boolean clickAllowed = true;
private boolean isRotateLeft = false;
private boolean isRotateRight = false;
/**
* Constructor initializes the InputSynchronizer with the application context.
* Sets up input mappings and listeners for user interactions.
@@ -54,6 +60,18 @@ public class InputSynchronizer {
setupInput();
}
public void update(float tpf) {
if(isRotateLeft && isRotateRight) {
return;
}
if(isRotateLeft) {
rotationAngle += 180 * tpf;
}
if(isRotateRight) {
rotationAngle -= 180 * tpf;
}
}
/**
* Configures input mappings for various actions and binds them to listeners.
*/
@@ -61,22 +79,22 @@ private void setupInput() {
inputManager.addMapping("Settings", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_RETURN));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_E));
inputManager.addMapping("RotateRightMouse", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addMapping("MouseLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); // Left movement
inputManager.addMapping("MouseRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); // Right movement
inputManager.addMapping("MouseVertical", new MouseAxisTrigger(MouseInput.AXIS_Y, false), new MouseAxisTrigger(MouseInput.AXIS_Y, true)); //Mouse Up Down movement
inputManager.addMapping("MouseScrollUp", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); // Scroll up
inputManager.addMapping("MouseScrollDown", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); // Scroll down
inputManager.addMapping("Test", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(actionListener, "Settings", "Forward", "RotateRightMouse", "Click", "Test");
inputManager.addListener(actionListener, "Settings", "Forward", "RotateRightMouse", "Click", "Left", "Right", "Test");
inputManager.addListener(analogListener, "MouseLeft", "MouseRight", "MouseScrollUp", "MouseScrollDown");
}
private boolean test = false;
UUID p = null;
/**
* Handles action-based input events such as key presses and mouse clicks.
*/
@@ -93,6 +111,10 @@ public void onAction(String name, boolean isPressed, float tpf) {
rightMousePressed = isPressed;
}
if(name.equals("Click") && isPressed) {
if(!clickAllowed) {
return;
}
if (app.getView() instanceof GameView gameView) {
DiceControl diceSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), DiceControl.class);
CardControl cardLayerSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), CardControl.class);
@@ -120,14 +142,50 @@ else if(boardSelect != null) {
}
}
if (name.equals("Left")) {
isRotateLeft = !isRotateLeft;
}
if (name.equals("Right")) {
isRotateRight = !isRotateRight;
}
if(name.equals("Test") &&isPressed){
if(app.getView() instanceof GameView gameView){
if(p == null) {
p = UUID.randomUUID();
gameView.getBoardHandler().addPlayer(Color.AIRFORCE,List.of(p,UUID.randomUUID(),UUID.randomUUID(),UUID.randomUUID()));
gameView.getBoardHandler().movePieceStartAnim(p,0);
gameView.getGuiHandler().addCardOwn(BonusCard.SHIELD);
gameView.getGuiHandler().setSelectableCards(List.of(BonusCard.SHIELD));
// gameView.getBoardHandler().movePieceAnim(p,0, 8);
} else {
// gameView.getBoardHandler().throwBombAnim(p);
gameView.getBoardHandler().throwPiece(p,Color.ARMY);
// gameView.getBoardHandler().movePieceAnim(p,0,20);
// gameView.getBoardHandler().throwPiece(p,Color.CYBER);
// gameView.getBoardHandler().throwPiece(p,Color.AIRFORCE);
//gameView.getBoardHandler().movePieceStartAnim(p,0);
}
// gameView.getGuiHandler().rollRankingResult(Color.AIRFORCE, 1);
// gameView.getGuiHandler().rollRankingResult(Color.ARMY, 2);
// gameView.getGuiHandler().rollRankingResult(Color.NAVY, 3);
// gameView.getGuiHandler().rollRankingResult(Color.CYBER, 4);
gameView.getGuiHandler().showDice();
// gameView.getGuiHandler().showDice();
// UUID p1 = UUID.randomUUID();
// gameView.getBoardHandler().addPlayer(Color.AIRFORCE,List.of(p1,UUID.randomUUID(),UUID.randomUUID(),UUID.randomUUID()));
// gameView.getBoardHandler().movePieceStartAnim(p1,0);
//gameView.getGuiHandler().drawCard(Color.ARMY);
//gameView.getGuiHandler().addCardOwn(BonusCard.SHIELD);
//gameView.getGuiHandler().playCardOwn(BonusCard.SHIELD);
}
}
}
@@ -302,4 +360,12 @@ public void setRotation(float rotationAngle){
public int getScroll() {
return scrollValue;
}
public void setClickAllowed(boolean allowed) {
clickAllowed = allowed;
}
public boolean isClickAllowed() {
return clickAllowed;
}
}

View File

@@ -1,13 +1,19 @@
package pp.mdga.client;
import com.jme3.app.SimpleApplication;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals;
import com.sun.tools.javac.Main;
import pp.mdga.client.acoustic.AcousticHandler;
import com.jme3.system.AppSettings;
import pp.mdga.client.dialog.JoinDialog;
import pp.mdga.client.view.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.prefs.Preferences;
@@ -39,19 +45,19 @@ public class MdgaApp extends SimpleApplication {
private MdgaState state = null;
/** Scale for rendering images. */
private float imageScale = prefs.getInt("scale", 1);
private final float imageScale = prefs.getInt("scale", 1);
/** The main menu view. */
private MdgaView mainView;
private MainView mainView;
/** The lobby view. */
private MdgaView lobbyView;
private LobbyView lobbyView;
/** The game view. */
private MdgaView gameView;
private GameView gameView;
/** The ceremony view. */
private MdgaView ceremonyView;
private CeremonyView ceremonyView;
/** The client game logic. */
private final ClientGameLogic clientGameLogic;
@@ -60,7 +66,7 @@ public class MdgaApp extends SimpleApplication {
private ServerConnection networkConnection;
private MdgaApp() {
public MdgaApp() {
networkConnection = new NetworkSupport(this);
this.clientGameLogic = new ClientGameLogic(networkConnection);
}
@@ -74,15 +80,30 @@ private MdgaApp() {
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setSamples(128);
settings.setWidth(prefs.getInt("width", 1280));
settings.setHeight(prefs.getInt("height", 720));
if(prefs.getBoolean("fullscreen", false)) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int screenWidth = (int) screenSize.getWidth();
int screenHeight = (int) screenSize.getHeight();
settings.setResolution(screenWidth, screenHeight);
settings.setFullscreen(true);
} else {
settings.setWidth(prefs.getInt("width", 1280));
settings.setHeight(prefs.getInt("height", 720));
}
settings.setCenterWindow(true);
settings.setVSync(false);
settings.setTitle("MDGA");
settings.setVSync(true);
MdgaApp app = new MdgaApp();
app.setSettings(settings);
app.setShowSettings(false);
app.setPauseOnLostFocus(false);
app.setDisplayStatView(false);
app.start();
}
@@ -120,6 +141,7 @@ public void simpleUpdate(float tpf) {
view.update(tpf);
acousticHandler.update();
notificationSynchronizer.update();
inputSynchronizer.update(tpf);
}
/**
@@ -245,30 +267,60 @@ public ServerConnection getNetworkSupport(){
return networkConnection;
}
public void updateResolution(int width, int height, float imageFactor) {
prefs.putInt("width", width);
prefs.putInt("height", height);
prefs.putFloat("scale", imageFactor);
public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) {
if(isFullscreen) {
int baseWidth = 1280;
int baseHeight = 720;
float baseAspectRatio = (float) baseWidth / baseHeight;
float newAspectRatio = (float) width / height;
try {
restartApp();
} catch (Exception e) {
//nothing
float scaleFactor = Math.max((float) width / baseWidth, (float) height / baseHeight);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int screenWidth = (int) screenSize.getWidth();
int screenHeight = (int) screenSize.getHeight();
settings.setResolution(screenWidth, screenHeight);
settings.setFullscreen(true);
prefs.putFloat("scale", scaleFactor);
prefs.putBoolean("fullscreen", true);
} else {
prefs.putInt("width", width);
prefs.putInt("height", height);
prefs.putFloat("scale", imageFactor);
prefs.putBoolean("fullscreen", false);
}
}
public static void restartApp() throws IOException {
String javaBin = System.getProperty("java.home") + "/bin/java";
String classPath = System.getProperty("java.class.path");
String className = System.getProperty("sun.java.command");
public static void restartApp() {
try {
String javaBin = System.getProperty("java.home") + "/bin/java";
String classPath = System.getProperty("java.class.path");
String className = System.getProperty("sun.java.command");
ProcessBuilder builder = new ProcessBuilder(
javaBin, "-cp", classPath, className
);
ProcessBuilder builder = new ProcessBuilder(
javaBin, "-cp", classPath, className
);
builder.start();
builder.start();
System.exit(0);
System.exit(0);
} catch (Exception e) {
throw new RuntimeException("restart failed");
}
}
public void afterGameCleanup() {
MainView main = (MainView) mainView;
main.getJoinDialog().disconnect();
main.getHostDialog().shutdownServer();
ceremonyView.afterGameCleanup();
}
public GameView getGameView(){
return gameView;
}
}

View File

@@ -145,4 +145,8 @@ public void enter(MdgaState state) {
public void setSwap(boolean swap){
this.swap = swap;
}
public void force() {
}
}

View File

@@ -19,39 +19,44 @@ public class NotificationSynchronizer {
this.app = app;
}
public void addTestNotification(Notification n) {
notifications.add(n);
handleGame(n);
}
public void update() {
Notification n = app.getGameLogic().getNotification();
if(n != null) {
switch (app.getState()) {
case MAIN:
handleMain(n);
break;
case LOBBY:
handleLobby(n);
break;
case GAME:
handleGame(n);
break;
case CEREMONY:
handleCeremony(n);
break;
case NONE:
throw new RuntimeException("no notification expected: " + n.toString());
while (n != null) {
if(n instanceof InfoNotification infoNotification) {
app.getView().showInfo(infoNotification.getMessage(), infoNotification.isError());
return;
}
if(n != null) {
switch (app.getState()) {
case MAIN:
handleMain(n);
break;
case LOBBY:
handleLobby(n);
break;
case GAME:
handleGame(n);
break;
case CEREMONY:
handleCeremony(n);
break;
case NONE:
throw new RuntimeException("no notification expected: " + n.getClass().getName());
}
}
n = app.getGameLogic().getNotification();
}
}
private void handleMain(Notification notification) {
if (notification instanceof LobbyDialogNotification) {
app.enter(MdgaState.LOBBY);
} else if (notification instanceof StartDialogNotification) {
//nothing
} else {
throw new RuntimeException("notification not expected: ");
throw new RuntimeException("notification not expected in main: "+ notification.getClass().getName());
}
}
@@ -61,16 +66,17 @@ private void handleLobby(Notification notification) {
if (notification instanceof TskSelectNotification n) {
lobbyView.setTaken(n.getColor(), true, n.isSelf(), n.getName());
} else if (notification instanceof StartDialogNotification) {
app.afterGameCleanup();
app.enter(MdgaState.MAIN);
} else if (notification instanceof TskUnselectNotification n) {
lobbyView.setTaken(n.getColor(), false, false, null);
} else if(notification instanceof LobbyReadyNotification lobbyReadyNotification) {
lobbyView.setReady(lobbyReadyNotification.getColor(), lobbyReadyNotification.isReady());
} else if (notification instanceof GameNotification n) {
app.getGameView().setOwnColor(n.getOwnColor());
app.enter(MdgaState.GAME);
((GameView) app.getView()).setOwnColor(n.getOwnColor());
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
throw new RuntimeException("notification not expected in lobby: " + notification.getClass().getName());
}
}
@@ -79,12 +85,13 @@ private void handleGame(Notification notification) {
GuiHandler guiHandler = gameView.getGuiHandler();
BoardHandler boardHandler = gameView.getBoardHandler();
ModelSynchronizer modelSynchronizer = app.getModelSynchronize();
Color ownColor = gameView.getOwnColor();
if (notification instanceof AcquireCardNotification n) {
guiHandler.addCard(n.getBonusCard());
guiHandler.addCardOwn(n.getBonusCard());
} else if (notification instanceof ActivePlayerNotification n) {
gameView.getGuiHandler().setActivePlayer(n.getColor());
boardHandler.showDice(n.getColor());
if(n.getColor() != ownColor) boardHandler.showDice(n.getColor());
} else if (notification instanceof CeremonyNotification ceremonyNotification) {
app.enter(MdgaState.CEREMONY);
CeremonyView ceremonyView = (CeremonyView) app.getView();
@@ -120,7 +127,7 @@ private void handleGame(Notification notification) {
boardHandler.movePieceHomeAnim(home.getPieceId(), home.getHomeIndex());
guiHandler.hideText();
} else if (notification instanceof InterruptNotification) {
app.enter(MdgaState.LOBBY);
gameView.enterInterrupt();
} else if (notification instanceof MovePieceNotification n) {
if(n.isMoveStart()) {
//StartMove
@@ -132,24 +139,20 @@ private void handleGame(Notification notification) {
}
guiHandler.hideText();
} else if (notification instanceof ThrowPieceNotification n) {
boardHandler.throwPieceAnim(n.getPieceId());
boardHandler.throwPiece(n.getPieceId(), n.getThrowColor());
} else if (notification instanceof NoShieldNotification n) {
boardHandler.unshieldPiece(n.getPieceId());
} else if (notification instanceof PlayCardNotification n) {
switch(n.getCard()){
case SWAP -> guiHandler.swap();
case TURBO -> guiHandler.turbo();
case SHIELD -> guiHandler.shield();
default -> throw new RuntimeException("invalid card");
}
if(n.getColor() == ownColor) guiHandler.playCardOwn(n.getCard());
else guiHandler.playCardEnemy(n.getColor(), n.getCard());
} else if (notification instanceof PlayerInGameNotification n) {
boardHandler.addPlayer(n.getColor(),n.getPiecesList());
guiHandler.addPlayer(n.getColor(),n.getName());
} else if (notification instanceof ResumeNotification) {
//TODO
gameView.leaveInterrupt();
} else if (notification instanceof RollDiceNotification n) {
gameView.getGuiHandler().hideText();
if(n.getColor() == gameView.getOwnColor()){
if(n.getColor() == ownColor){
guiHandler.rollDice(n.getEyes(), n.isTurbo() ? n.getMultiplier() : -1);
}
else {
@@ -164,6 +167,7 @@ private void handleGame(Notification notification) {
} else if (notification instanceof ShieldSuppressedNotification n) {
boardHandler.suppressShield(n.getPieceId());
} else if (notification instanceof StartDialogNotification) {
app.afterGameCleanup();
app.enter(MdgaState.MAIN);
} else if (notification instanceof SwapPieceNotification n) {
// boardHandler.swapPieces(n.getFirstPiece(), n.getSecondPiece());
@@ -184,15 +188,16 @@ private void handleGame(Notification notification) {
} else if (notification instanceof FinishNotification n){
guiHandler.finish(n.getColorFinished());
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
throw new RuntimeException("notification not expected in game: " + notification.getClass().getName());
}
}
private void handleCeremony(Notification notification) {
if (notification instanceof StartDialogNotification) {
app.afterGameCleanup();
app.enter(MdgaState.MAIN);
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
throw new RuntimeException("notification not expected in ceremony: " + notification.getClass().getName());
}
}
}

View File

@@ -0,0 +1,47 @@
package pp.mdga.client;
import com.jme3.math.Vector3f;
public class Util {
private Util(){}
/**
* Performs linear interpolation between two values.
*
* @param start The starting value.
* @param end The ending value.
* @param t A parameter between 0 and 1 representing the interpolation progress.
* @return The interpolated value.
*/
public static float linInt(float start, float end, float t) {
return start + t * (end - start);
}
/**
* Performs quadratic interpolation between three points.
*
* @param p1 The initial point.
* @param p2 The middle point.
* @param p3 The final point.
* @param t The interpolation parameter (0 <= t <= 1).
* @return The interpolated point.
*/
public static Vector3f quadInt(Vector3f p1, Vector3f p2, Vector3f p3, float t) {
// Quadratic interpolation: (1-t)^2 * p1 + 2 * (1-t) * t * p2 + t^2 * p3
float oneMinusT = 1 - t;
return p1.mult(oneMinusT * oneMinusT)
.add(p2.mult(2 * oneMinusT * t))
.add(p3.mult(t * t));
}
/**
* A smooth ease-in-out function for interpolation.
* It accelerates and decelerates the interpolation for a smoother effect.
*
* @param x The interpolation parameter (0 <= x <= 1).
* @return The adjusted interpolation value.
*/
public static float easeInOut(float x){
return x < 0.5 ? 4 * x * x * x : (float) (1 - Math.pow(-2 * x + 2, 3) / 2);
}
}

View File

@@ -109,6 +109,29 @@ public void playSound(MdgaSound sound) {
case LEAVE:
assets.add(new SoundAssetDelayVolume(SoundAsset.UI_SOUND2, 0.6f, 0.0f));
break;
case JET:
assets.add(new SoundAssetDelayVolume(SoundAsset.JET, 1.0f, 0.0f));
break;
case EXPLOSION:
assets.add(new SoundAssetDelayVolume(SoundAsset.EXPLOSION_1, 1.0f, 4f));
assets.add(new SoundAssetDelayVolume(SoundAsset.EXPLOSION_2, 1.0f, 4f));
assets.add(new SoundAssetDelayVolume(SoundAsset.THUNDER, 1.0f, 4f));
break;
case LOSE:
assets.add(new SoundAssetDelayVolume(SoundAsset.LOSE, 1.0f, 0.0f));
break;
case BONUS:
assets.add(new SoundAssetDelayVolume(SoundAsset.BONUS, 1.0f, 0.0f));
break;
case TURRET_ROTATE:
assets.add(new SoundAssetDelayVolume(SoundAsset.TURRET_ROTATE, 0.7f, 0f));
break;
case TANK_SHOOT:
assets.add(new SoundAssetDelayVolume(SoundAsset.TANK_SHOOT, 0.7f, 0f));
break;
case TANK_EXPLOSION:
assets.add(new SoundAssetDelayVolume(SoundAsset.EXPLOSION_1, 1.0f, 0f));
break;
default:
break;
}

View File

@@ -31,4 +31,11 @@ public enum MdgaSound {
OTHER_CONNECTED,
NOT_READY,
LEAVE,
JET,
EXPLOSION,
LOSE,
BONUS,
TURRET_ROTATE,
TANK_SHOOT,
TANK_EXPLOSION
}

View File

@@ -28,7 +28,18 @@ enum SoundAsset {
POWERUP("powerup.wav"),
ROBOT_READY("robotReady.wav"),
UNIT_READY("unitReady.wav"),
CONNECTED("connected.wav");
JET("jet-overhead.wav"),
EXPLOSION_1("exp.ogg"),
EXPLOSION_2("exp2.ogg"),
THUNDER("thunder.ogg"),
UI90("ui90.ogg"),
BONUS("bonus.ogg"),
LOSE("lose.ogg"),
CONNECTED("connected.wav"),
TURRET_ROTATE("turret_rotate.ogg"),
TANK_SHOOT("tank_shoot.ogg")
;
private final String path;

View File

@@ -0,0 +1,18 @@
package pp.mdga.client.animation;
import pp.mdga.client.InitControl;
public class ActionControl extends InitControl {
private final Runnable runnable;
public ActionControl(Runnable runnable){
this.runnable = runnable;
}
protected void action(){
if(runnable == null) throw new RuntimeException("runnable is null");
else runnable.run();
}
}

View File

@@ -0,0 +1,126 @@
package pp.mdga.client.animation;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.MdgaApp;
public class Explosion {
private final Node rootNode;
private final MdgaApp app;
private final Vector3f location;
private ParticleEmitter fire;
private ParticleEmitter smoke;
private boolean triggered = false;
private final Material mat;
/**
* Konstruktor für die Explosion.
*
* @param app Die Hauptanwendung.
* @param rootNode Der Root-Knoten, an den die Explosion angefügt wird.
* @param location Der Ort der Explosion in World-Koordinaten.
*/
public Explosion(MdgaApp app, Node rootNode, Vector3f location) {
this.app = app;
this.rootNode = rootNode;
this.location = location;
this.mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
mat.getAdditionalRenderState().setDepthWrite(false);
mat.getAdditionalRenderState().setDepthTest(false);
}
/**
* Initialisiert den Partikel-Emitter für die Explosion.
*/
private void initializeEmitter() {
fire = new ParticleEmitter("Effect", Type.Triangle,50);
fire.setMaterial(mat);
fire.setStartColor(ColorRGBA.Yellow);
fire.setEndColor(ColorRGBA.Red);
fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0.2f,0.2f,4f));
fire.getParticleInfluencer().setVelocityVariation(0.4f);
fire.setStartSize(0.1f);
fire.setEndSize(0.8f);
fire.setGravity(0, 0, -0.1f);
fire.setLowLife(0.5f);
fire.setHighLife(2.2f);
fire.setParticlesPerSec(0);
fire.setLocalTranslation(location);
fire.move(0, 0, 45);
smoke = new ParticleEmitter("Effect2", Type.Triangle,40);
smoke.setMaterial(mat);
smoke.setImagesX(2);
smoke.setImagesY(2);
smoke.setStartColor(ColorRGBA.DarkGray);
smoke.setEndColor(new ColorRGBA(0.05f, 0.05f, 0.05f, 1));
smoke.getParticleInfluencer().setInitialVelocity(new Vector3f(0.0f,0.0f,0.7f));
smoke.getParticleInfluencer().setVelocityVariation(0.5f);
smoke.setStartSize(0.2f);
smoke.setEndSize(0.5f);
smoke.setGravity(0, 0, -0.3f);
smoke.setLowLife(1.2f);
smoke.setHighLife(5.5f);
smoke.setParticlesPerSec(0);
smoke.setLocalTranslation(location);
smoke.move(0, 0, 45);
}
/**
* Löst die Explosion aus.
*/
public void trigger() {
if (!triggered) {
triggered = true;
initializeEmitter();
}
rootNode.attachChild(fire);
fire.emitAllParticles();
fire.addControl(new AbstractControl() {
private float elapsedTime = 0;
@Override
protected void controlUpdate(float tpf) {
elapsedTime += tpf;
if (elapsedTime > 10f) {
rootNode.detachChild(fire);
fire.removeControl(this);
}
}
@Override
protected void controlRender(com.jme3.renderer.RenderManager rm, com.jme3.renderer.ViewPort vp) {}
});
rootNode.attachChild(smoke);
smoke.emitAllParticles();
smoke.addControl(new AbstractControl() {
private float elapsedTime = 0;
@Override
protected void controlUpdate(float tpf) {
elapsedTime += tpf;
if (elapsedTime > 10f) {
rootNode.detachChild(smoke);
smoke.removeControl(this);
}
}
@Override
protected void controlRender(com.jme3.renderer.RenderManager rm, com.jme3.renderer.ViewPort vp) {}
});
}
}

View File

@@ -0,0 +1,70 @@
package pp.mdga.client.animation;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import pp.mdga.client.InitControl;
import static pp.mdga.client.Util.linInt;
public class FadeControl extends ActionControl {
private float duration; // Duration of the fade effect
private float timeElapsed = 0;
private boolean init = false;
private float startAlpha;
private float endAlpha;
public FadeControl(float duration, float startAlpha, float endAlpha, Runnable actionAfter) {
super(actionAfter);
this.duration = duration;
this.startAlpha = startAlpha;
this.endAlpha = endAlpha;
}
public FadeControl(float duration, float startAlpha, float endAlpha) {
this(duration, startAlpha, endAlpha, null);
}
@Override
protected void initSpatial() {
init = true;
}
@Override
protected void controlUpdate(float tpf) {
if (!init) return;
timeElapsed += tpf;
float t = timeElapsed / duration; // Calculate progress (0 to 1)
if (t >= 1) {
// Fade complete
t = 1;
init = false;
spatial.removeControl(this);
action();
}
float alpha = linInt(startAlpha, endAlpha, t); // Interpolate alpha
// Update the material's alpha
if (spatial instanceof Geometry geometry) {
Material mat = geometry.getMaterial();
if (mat != null) {
ColorRGBA diffuse = (ColorRGBA) mat.getParam("Diffuse").getValue();
mat.setColor("Diffuse", new ColorRGBA(diffuse.r, diffuse.g, diffuse.b, alpha));
ColorRGBA ambient = (ColorRGBA) mat.getParam("Ambient").getValue();
mat.setColor("Ambient", new ColorRGBA(ambient.r, ambient.g, ambient.b, alpha));
// Disable shadows when the object is nearly invisible
if (alpha <= 0.1f) {
geometry.setShadowMode(RenderQueue.ShadowMode.Off);
} else {
geometry.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
}
} else throw new RuntimeException("Material is null");
} else throw new RuntimeException("Spatial is not instance of Geometry");
}
}

View File

@@ -0,0 +1,178 @@
package pp.mdga.client.animation;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.view.GameView;
import java.util.UUID;
public class JetAnimation {
private final MdgaApp app; // Referenz auf die Hauptanwendung
private final Node rootNode; // Root-Knoten, an dem die Animation hängt
private Spatial jetModel; // Das Model des "jet"
private final Vector3f spawnPoint; // Spawnpunkt des Jets
private final Vector3f nodePoint; // Punkt des überflogenen Knotens
private final Vector3f despawnPoint; // Punkt, an dem der Jet despawnt
private final float curveHeight; // Maximale Höhe der Kurve
private final float animationDuration; // Dauer der Animation
private Explosion explosion;
private final UUID id;
private Runnable actionAfter;
/**
* Konstruktor für die ThrowAnimation-Klasse.
*
* @param app Die Hauptanwendung
* @param rootNode Der Root-Knoten, an dem der Jet angefügt wird
* @param uuid Die UUID des pieces
* @param targetPoint Der Punkt, an dem der Jet spawnt
* @param curveHeight Die maximale Höhe der Flugkurve
* @param animationDuration Die Gesamtdauer der Animation in Sekunden
*/
public JetAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f targetPoint, float curveHeight, float animationDuration, Runnable actionAfter) {
Vector3f spawnPoint = targetPoint.add(170, 50, 50);
Vector3f controlPoint = targetPoint.add(new Vector3f(0, 0, -45));
Vector3f despawnPoint = targetPoint.add(-100, -100, 40);
this.app = app;
this.rootNode = rootNode;
this.spawnPoint = spawnPoint;
this.nodePoint = controlPoint;
this.despawnPoint = despawnPoint;
this.curveHeight = curveHeight;
this.animationDuration = animationDuration;
id = uuid;
explosion = new Explosion(app, rootNode, nodePoint);
this.actionAfter = actionAfter;
}
/**
* Startet die Animation.
*/
public void start() {
app.getAcousticHandler().playSound(MdgaSound.JET);
spawnJet();
animateJet();
}
/**
* Spawnt den Jet an der spezifizierten Position.
*/
private void spawnJet() {
jetModel = app.getAssetManager().loadModel(Asset.jet.getModelPath());
jetModel.setLocalTranslation(spawnPoint);
jetModel.scale(Asset.jet.getSize());
jetModel.rotate(FastMath.HALF_PI, 0, 0);
jetModel.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(Asset.jet.getDiffPath()));
jetModel.setMaterial(mat);
rootNode.attachChild(jetModel);
app.getAcousticHandler().playSound(MdgaSound.EXPLOSION);
}
/**
* Animiert den Jet entlang einer Kurve und lässt ihn anschließend verschwinden.
*/
private void animateJet() {
Vector3f controlPoint1 = spawnPoint.add(0, curveHeight, 0);
Vector3f controlPoint2 = nodePoint.add(0, curveHeight, 0);
BezierCurve3f curve = new BezierCurve3f(spawnPoint, controlPoint1, controlPoint2, despawnPoint);
app.getRootNode().addControl(new AbstractControl() {
private float elapsedTime = 0;
@Override
protected void controlUpdate(float tpf) {
elapsedTime += tpf;
float progress = elapsedTime / animationDuration;
if(elapsedTime > 4.2f) {
explosion.trigger();
}
if (progress > 1) {
rootNode.detachChild(jetModel);
this.spatial.removeControl(this);
} else {
Vector3f currentPos = curve.interpolate(progress);
Vector3f direction = curve.interpolateDerivative(progress).normalizeLocal();
jetModel.setLocalTranslation(currentPos);
jetModel.lookAt(currentPos.add(direction), Vector3f.UNIT_Z);
jetModel.rotate(-FastMath.HALF_PI, 0, (float) Math.toRadians(-25));
}
if (elapsedTime > 6.0f) {
endAnim();
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// Wird hier nicht benötigt
}
});
}
private void endAnim(){
actionAfter.run();
}
/**
* Repräsentiert eine 3D-Bezier-Kurve mit vier Kontrollpunkten.
*/
private static class BezierCurve3f {
private final Vector3f p0, p1, p2, p3;
public BezierCurve3f(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public Vector3f interpolate(float t) {
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
Vector3f point = p0.mult(uuu);
point = point.add(p1.mult(3 * uu * t));
point = point.add(p2.mult(3 * u * tt));
point = point.add(p3.mult(ttt));
return point;
}
public Vector3f interpolateDerivative(float t) {
float u = 1 - t;
float tt = t * t;
Vector3f derivative = p0.mult(-3 * u * u);
derivative = derivative.add(p1.mult(3 * u * u - 6 * u * t));
derivative = derivative.add(p2.mult(6 * u * t - 3 * tt));
derivative = derivative.add(p3.mult(3 * tt));
return derivative;
}
}
}

View File

@@ -0,0 +1,200 @@
package pp.mdga.client.animation;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import pp.mdga.client.InitControl;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
import java.util.*;
public class MatrixAnimation extends ActionControl {
private MdgaApp app;
private static final Random RANDOM = new Random();
private Vector3f radarPos;
private Runnable runnable;
private boolean init = false;
private List<ParticleEmitter> activeEmitter = new ArrayList<>();
private ParticleEmitter radarEmitter = null;
private float timeElapsed = 0f;
private enum MatrixState{
RADAR_ON,
RADAR_OFF,
MATRIX_ON,
MATRIX_OFF
}
private MatrixState state;
public MatrixAnimation(MdgaApp app, Vector3f radarPos, Runnable runnable){
super(runnable);
this.app = app;
this.radarPos = radarPos;
}
@Override
protected void initSpatial() {
state = MatrixState.RADAR_ON;
timeElapsed = 0;
init = true;
radar();
}
@Override
protected void controlUpdate(float tpf) {
if(!init) return;
timeElapsed += tpf;
switch(state){
case RADAR_ON -> {
if(timeElapsed >= 2f){
state = MatrixState.RADAR_OFF;
timeElapsed = 0;
radarEmitter.setParticlesPerSec(0);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
app.getRootNode().detachChild(radarEmitter);
}
}, 3000);
}
}
case RADAR_OFF -> {
if(timeElapsed >= 0.1f){
state = MatrixState.MATRIX_ON;
timeElapsed = 0;
matrix();
}
}
case MATRIX_ON -> {
if(timeElapsed >= 3f){
state = MatrixState.MATRIX_OFF;
timeElapsed = 0;
turnOff();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
for (ParticleEmitter particleEmitter : activeEmitter){
app.getRootNode().detachChild(particleEmitter);
}
}
}, 3000);
}
}
case MATRIX_OFF -> {
if(timeElapsed >= 0.5f){
init = false;
spatial.removeControl(this);
action();
}
}
}
}
private void turnOff(){
for (ParticleEmitter particleEmitter : activeEmitter){
particleEmitter.setParticlesPerSec(0f);
}
}
private void radar(){
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
mat.setTexture("Texture", app.getAssetManager().loadTexture("Images/particle/radar_beam.png"));
ParticleEmitter emitter = new ParticleEmitter("Effect", Type.Triangle, 50);
emitter.setMaterial(mat);
emitter.setImagesX(1); // columns
emitter.setImagesY(1); // rows
emitter.setSelectRandomImage(true);
emitter.setStartColor(ColorRGBA.White);
emitter.setEndColor(ColorRGBA.Black);
emitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0f, 0f, 2));
emitter.getParticleInfluencer().setVelocityVariation(0f);
emitter.setStartSize(0.1f);
emitter.setEndSize(10);
emitter.setGravity(0, 0, 0);
float life = 2.6f;
emitter.setLowLife(life);
emitter.setHighLife(life);
emitter.setLocalTranslation(radarPos.add(new Vector3f(0,0,5)));
emitter.setParticlesPerSec(1.8f);
app.getRootNode().attachChild(emitter);
radarEmitter = emitter;
}
private void matrix(){
for(int i = 0; i < 5; i++){
particleStream(
generateMatrixColor(),
generateMatrixColor(),
getRandomFloat(0,1f),
getRandomPosition(),
getRandomFloat(1,2)
);
}
}
private void particleStream(ColorRGBA start, ColorRGBA end, float speedVar, Vector3f pos, float spawnVar){
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
mat.setTexture("Texture", app.getAssetManager().loadTexture("Images/particle/particle_cir.png"));
ParticleEmitter matrix = new ParticleEmitter("Effect", Type.Triangle, 50);
matrix.setMaterial(mat);
matrix.setImagesX(2); // columns
matrix.setImagesY(1); // rows
matrix.setSelectRandomImage(true);
matrix.setStartColor(start);
matrix.setEndColor(end);
matrix.getParticleInfluencer().setInitialVelocity(new Vector3f(0f, 0f, -6f - speedVar));
matrix.getParticleInfluencer().setVelocityVariation(0f);
matrix.setStartSize(0.4f);
matrix.setEndSize(0.6f);
matrix.setGravity(0, 0, 2f);
matrix.setLowLife(3f);
matrix.setHighLife(3f);
matrix.setLocalTranslation(spatial.getLocalTranslation().add(pos).add(new Vector3f(0,0,15)));
matrix.setParticlesPerSec(spawnVar);
app.getRootNode().attachChild(matrix);
activeEmitter.add(matrix);
}
public static Vector3f getRandomPosition() {
// Generate a random angle in radians (0 to 2π)
float angle = (float) (2 * Math.PI * RANDOM.nextDouble());
// Generate a random radius with uniform distribution
float radius = (float) Math.sqrt(RANDOM.nextDouble());
radius *= 1f;
// Convert polar coordinates to Cartesian
float x = radius * (float) Math.cos(angle);
float y = radius * (float) Math.sin(angle);
return new Vector3f(x,y,0);
}
public static float getRandomFloat(float start, float end) {
if (start > end) {
throw new IllegalArgumentException("Start must be less than or equal to end.");
}
return start + RANDOM.nextFloat() * (end - start);
}
public static ColorRGBA generateMatrixColor() {
// Red is dominant
float red = 0.8f + RANDOM.nextFloat() * 0.2f; // Red channel: 0.8 to 1.0
// Green is moderately high
float green = 0.4f + RANDOM.nextFloat() * 0.3f; // Green channel: 0.4 to 0.7
// Blue is minimal
float blue = RANDOM.nextFloat() * 0.2f; // Blue channel: 0.0 to 0.2
float alpha = 1.0f; // Fully opaque
return new ColorRGBA(red, green, blue, alpha);
}
}

View File

@@ -1,7 +1,8 @@
package pp.mdga.client.animation;
import com.jme3.math.Vector3f;
import pp.mdga.client.InitControl;
import static pp.mdga.client.Util.*;
/**
* A control that smoothly moves a spatial from an initial position to an end position
@@ -12,16 +13,16 @@
* an ease-in-out curve to create a smooth start and stop effect.
* </p>
*/
public class MoveControl extends InitControl {
public class MoveControl extends ActionControl {
private boolean moving;
private final Vector3f initPos;
private final Vector3f endPos;
private final Vector3f middlePos;
private final static float HEIGHT = 2;
private final static float MOVE_SPEED = 1f;
private float progress = 0;
private final Runnable actionAfter;
private final float height;
private final float duration;
private float timer = 0;
private boolean easing;
/**
* Creates a new MoveControl with specified initial and end positions, and an action to run after the movement.
@@ -32,15 +33,22 @@ public class MoveControl extends InitControl {
* @param actionAfter A Runnable that will be executed after the movement finishes.
*/
public MoveControl(Vector3f initPos, Vector3f endPos, Runnable actionAfter){
this(initPos, endPos, actionAfter, 2, 1, true);
}
public MoveControl(Vector3f initPos, Vector3f endPos, Runnable actionAfter, float height, float duration, boolean easing){
super(actionAfter);
moving = false;
this.initPos = initPos;
this.endPos = endPos;
this.height = height;
this.duration = duration;
this.easing = easing;
middlePos = new Vector3f(
(initPos.x + endPos.x) / 2,
(initPos.y + endPos.y) / 2,
HEIGHT
(initPos.x + endPos.x) / 2,
(initPos.y + endPos.y) / 2,
height
);
this.actionAfter = actionAfter;
}
/**
@@ -50,7 +58,7 @@ public MoveControl(Vector3f initPos, Vector3f endPos, Runnable actionAfter){
@Override
protected void initSpatial() {
moving = true;
progress = 0;
timer = 0;
}
/**
@@ -63,10 +71,16 @@ protected void initSpatial() {
@Override
protected void controlUpdate(float tpf) {
if(!moving) return;
progress += tpf * MOVE_SPEED;
if(progress > 1) progress = 1;
spatial.setLocalTranslation(quadInt(initPos,middlePos,endPos, easeInOut(progress)));
if(progress == 1) end();
timer += tpf;
float t = timer / duration;
if (t >= 1) t = 1;
float interpolated = easing ? easeInOut(t) : t;
spatial.setLocalTranslation(quadInt(initPos,middlePos,endPos, interpolated));
if(t >= 1) end();
}
/**
@@ -75,35 +89,11 @@ protected void controlUpdate(float tpf) {
*/
private void end(){
moving = false;
actionAfter.run();
spatial.removeControl(this);
action();
}
/**
* Performs quadratic interpolation between three points.
*
* @param p1 The initial point.
* @param p2 The middle point.
* @param p3 The final point.
* @param t The interpolation parameter (0 <= t <= 1).
* @return The interpolated point.
*/
private Vector3f quadInt(Vector3f p1, Vector3f p2, Vector3f p3, float t) {
// Quadratic interpolation: (1-t)^2 * p1 + 2 * (1-t) * t * p2 + t^2 * p3
float oneMinusT = 1 - t;
return p1.mult(oneMinusT * oneMinusT)
.add(p2.mult(2 * oneMinusT * t))
.add(p3.mult(t * t));
}
/**
* A smooth ease-in-out function for interpolation.
* It accelerates and decelerates the interpolation for a smoother effect.
*
* @param x The interpolation parameter (0 <= x <= 1).
* @return The adjusted interpolation value.
*/
private float easeInOut(float x){
return x < 0.5 ? 4 * x * x * x : (float) (1 - Math.pow(-2 * x + 2, 3) / 2);
}
}

View File

@@ -0,0 +1,167 @@
package pp.mdga.client.animation;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import pp.mdga.client.Asset;
import pp.mdga.client.InitControl;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.board.TankTopControl;
import java.util.Timer;
import java.util.TimerTask;
import static com.jme3.material.Materials.LIGHTING;
import static com.jme3.material.Materials.UNSHADED;
public class ShellAnimation extends ActionControl {
private static final float FLYING_DURATION = 1.25f;
private static final float FLYING_HEIGHT = 12f;
private TankTopControl tankTopControl;
private MdgaApp app;
public ShellAnimation(TankTopControl tankTopControl, MdgaApp app, Runnable actionAfter){
super(actionAfter);
this.tankTopControl = tankTopControl;
this.app = app;
}
@Override
protected void initSpatial() {
tankTopControl.rotate(spatial.getLocalTranslation(), this::shoot);
app.getAcousticHandler().playSound(MdgaSound.TURRET_ROTATE);
app.getRootNode().attachChild(createShell());
}
private Vector3f getShootPos(){
Vector3f localOffset = new Vector3f(0, -5.4f, 2.9f);
Quaternion turretRotation = tankTopControl.getSpatial().getLocalRotation();
Vector3f transformedOffset = turretRotation.mult(localOffset);
return tankTopControl.getSpatial().getLocalTranslation().add(transformedOffset);
}
private void shoot(){
app.getAcousticHandler().playSound(MdgaSound.TANK_SHOOT);
Vector3f shootPos = getShootPos();
createEffect(
shootPos,
"Images/particle/flame.png",
2, 2,
1, 3,
1f,
0.3f, 0.7f,
new ColorRGBA(1f, 0.8f, 0.4f, 0.5f),
new ColorRGBA(1f, 0f, 0f, 0f)
);
createEffect(
shootPos,
"Images/particle/vapor_cloud.png",
3, 3,
0.3f, 0.8f,
10,
0.1f, 0.35f,
new ColorRGBA(0.5f,0.5f,0.5f,0.5f),
ColorRGBA.Black
);
Spatial shell = createShell();
app.getRootNode().attachChild(shell);
shell.addControl(new ShellControl(this::hitExplosion, shootPos, spatial.getLocalTranslation(), FLYING_HEIGHT, FLYING_DURATION, app.getAssetManager()));
}
private Spatial createShell(){
Spatial model = app.getAssetManager().loadModel(Asset.shell.getModelPath());
model.scale(.16f);
model.setLocalTranslation(tankTopControl.getSpatial().getLocalTranslation());
Vector3f shootPos = tankTopControl.getSpatial().getLocalTranslation();
Vector3f targetPos = spatial.getLocalTranslation();
Vector3f direction = targetPos.subtract(shootPos).normalize();
Quaternion rotation = new Quaternion();
rotation.lookAt(direction, new Vector3f(1,0,0)); // Assuming UNIT_Y is the up vector
model.setLocalRotation(rotation);
model.rotate(FastMath.HALF_PI,0,0);
Material mat = new Material(app.getAssetManager(), LIGHTING);
mat.setBoolean("UseMaterialColors", true);
ColorRGBA color = ColorRGBA.fromRGBA255(143,117,0,255);
mat.setColor("Diffuse", color);
mat.setColor("Ambient", color);
model.setMaterial(mat);
return model;
}
private void hitExplosion(){
app.getAcousticHandler().playSound(MdgaSound.TANK_EXPLOSION);
createEffect(
spatial.getLocalTranslation().setZ(1),
"Images/particle/flame.png",
2, 2,
1, 5,
2f,
0.3f, 0.7f,
new ColorRGBA(1f, 0.8f, 0.4f, 0.5f),
new ColorRGBA(1f, 0f, 0f, 0f)
);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
action();
}
}, 800);
}
private void createEffect(Vector3f shootPos,
String image,
int x, int y,
float startSize, float endSize,
float velocity,
float lowLife, float highLife,
ColorRGBA start, ColorRGBA end){
// Create a particle emitter for the explosion
ParticleEmitter explosionEmitter = new ParticleEmitter("Explosion", ParticleMesh.Type.Triangle, 100);
Material explosionMat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
explosionMat.setTexture("Texture", app.getAssetManager().loadTexture(image));
explosionEmitter.setMaterial(explosionMat);
// Particle properties
explosionEmitter.setImagesX(x); // Columns in the texture
explosionEmitter.setImagesY(y); // Rows in the texture
explosionEmitter.setSelectRandomImage(true); // Randomize images for variety
explosionEmitter.setStartColor(start); // Bright yellowish orange
explosionEmitter.setEndColor(end); // Fade to transparent red
explosionEmitter.setStartSize(startSize); // Initial size
explosionEmitter.setEndSize(endSize); // Final size
explosionEmitter.setLowLife(lowLife); // Minimum lifetime of particles
explosionEmitter.setHighLife(highLife); // Maximum lifetime of particles
explosionEmitter.setGravity(0, 0, 1); // Gravity to pull particles down
explosionEmitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, velocity));
explosionEmitter.getParticleInfluencer().setVelocityVariation(1f); // Adds randomness to the initial velocity
explosionEmitter.setFacingVelocity(true); // Particles face their velocity direction
explosionEmitter.setLocalTranslation(shootPos);
explosionEmitter.setParticlesPerSec(0);
explosionEmitter.emitAllParticles();
app.getRootNode().attachChild(explosionEmitter);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
app.getRootNode().detachChild(explosionEmitter);
}
}, 1000);
}
}

View File

@@ -0,0 +1,89 @@
package pp.mdga.client.animation;
import com.jme3.asset.AssetManager;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import pp.mdga.client.InitControl;
public class ShellControl extends ActionControl {
private final Vector3f shootPos;
private final Vector3f endPos;
private final float height;
private final float duration;
private Vector3f oldPos;
private ParticleEmitter emitter;
private AssetManager assetManager;
public ShellControl(Runnable runnable, Vector3f shootPos, Vector3f endPos, float height, float duration, AssetManager assetManager){
super(runnable);
this.shootPos = shootPos;
this.endPos = endPos;
this.height = height;
this.duration = duration;
this.assetManager = assetManager;
}
@Override
protected void initSpatial() {
spatial.addControl(new MoveControl(
shootPos,
endPos,
()->{
emitter.killAllParticles();
emitter.setParticlesPerSec(0);
emitter.removeFromParent();
spatial.removeControl(this);
spatial.removeFromParent();
action();
},
height,
duration,
false
));
oldPos = spatial.getLocalTranslation().clone();
createEmitter();
}
private void createEmitter() {
emitter = new ParticleEmitter("ShellTrail", ParticleMesh.Type.Triangle, 200);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat.setTexture("Texture", assetManager.loadTexture("Images/particle/line.png")); // Nutze eine schmale, linienartige Textur
emitter.setMaterial(mat);
// Comic-Style Farben
emitter.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f)); // Reinweiß
emitter.setEndColor(new ColorRGBA(1f, 1f, 1f, 0f)); // Transparent
// Partikelgröße und Lebensdauer
emitter.setStartSize(0.15f); // Startgröße
emitter.setEndSize(0.1f); // Endgröße
emitter.setLowLife(0.14f); // Sehr kurze Lebensdauer
emitter.setHighLife(0.14f);
emitter.setGravity(0, 0, 0); // Keine Gravitation
emitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0));
emitter.getParticleInfluencer().setVelocityVariation(0f); // Kein Variationsspielraum
// Hohe Dichte für eine glatte Spur
emitter.setParticlesPerSec(500);
// Zur Shell hinzufügen
spatial.getParent().attachChild(emitter);
}
@Override
protected void controlUpdate(float tpf) {
Vector3f direction = spatial.getLocalTranslation().subtract(oldPos).normalize();
if (direction.lengthSquared() > 0) {
spatial.getLocalRotation().lookAt(direction, Vector3f.UNIT_X);
spatial.rotate(FastMath.HALF_PI,0,0);
}
oldPos = spatial.getLocalTranslation().clone();
emitter.setLocalTranslation(spatial.getLocalTranslation().clone());
}
}

View File

@@ -1,6 +1,9 @@
package pp.mdga.client.board;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.renderer.queue.RenderQueue;
@@ -9,10 +12,10 @@
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.animation.MoveControl;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.animation.*;
import pp.mdga.client.gui.DiceControl;
import pp.mdga.game.Color;
import pp.mdga.game.Piece;
import java.util.*;
@@ -54,6 +57,10 @@ public class BoardHandler {
private PieceControl selectedOwnPiece;
private PieceControl selectedEnemyPiece;
private DiceControl diceControl;
//Radar Position for Matrix animation
private Vector3f radarPos;
//TankTop for shellAnimation
private TankTopControl tankTop;
/**
* Creates a new BoardHandler.
@@ -146,12 +153,24 @@ private void initMap() {
case node_wait_blue -> addHomeNode(waitingNodesMap, Color.NAVY, assetOnMap);
case node_wait_green -> addHomeNode(waitingNodesMap, Color.ARMY, assetOnMap);
case node_wait_yellow -> addHomeNode(waitingNodesMap, Color.CYBER, assetOnMap);
case radar -> addRadar(assetOnMap);
case tankShoot -> addTankShoot(assetOnMap);
default -> displayAsset(assetOnMap);
}
}
}
private void addTankShoot(AssetOnMap assetOnMap) {
displayAsset(assetOnMap);
tankTop = displayAndControl(new AssetOnMap(Asset.tankShootTop, assetOnMap.x(), assetOnMap.y(), assetOnMap.rot()), new TankTopControl());
}
private void addRadar(AssetOnMap assetOnMap) {
radarPos = gridToWorld(assetOnMap.x(), assetOnMap.y());
displayAsset(assetOnMap);
}
/**
* Converts an asset to its corresponding color.
*
@@ -185,11 +204,16 @@ private Spatial createModel(Asset asset, Vector3f pos, float rot) {
model.rotate((float) Math.toRadians(0), 0, (float) Math.toRadians(rot));
model.setLocalTranslation(pos);
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
mat.setBoolean("UseMaterialColors", true); // Required for Material Colors
mat.setColor("Diffuse", new ColorRGBA(1, 1, 1, 1)); // White color with full alpha
mat.setColor("Ambient", new ColorRGBA(1, 1, 1, 1)); // Ambient color with full alpha
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
model.setMaterial(mat);
rootNodeBoard.attachChild(model);
rootNodeBoard.attachChild(model);
return model;
}
@@ -443,6 +467,7 @@ private void throwPiece(UUID uuid){
// Synchronisation oder Animation
pieceControl.rotateInit();
app.getAcousticHandler().playSound(MdgaSound.LOSE);
app.getModelSynchronize().animationEnd();
}
@@ -720,10 +745,52 @@ public void movePieceStartAnim(UUID uuid, int moveIndex){
*/
public void throwPieceAnim(UUID uuid){
pieces.get(uuid).getSpatial().addControl(new MoveControl(
pieces.get(uuid).getLocation(),
getNextWaitingNode(pieceColor.get(uuid)).getLocation(),
()->throwPiece(uuid)
));
pieces.get(uuid).getLocation(), getNextWaitingNode(pieceColor.get(uuid)).getLocation(),
()->throwPiece(uuid))
);
}
public void throwPiece(UUID uuid, Color throwColor){
switch(throwColor){
case ARMY -> throwShell(uuid);
case NAVY -> throwMissle(uuid);
case CYBER -> throwMatrix(uuid);
case AIRFORCE -> throwBomb(uuid);
default -> throw new RuntimeException("invalid color");
}
}
/**
* Animates the throwing of a piece to the next available waiting node.
*
* @param uuid the UUID of the piece to animate
*/
private void throwBomb(UUID uuid) {
Vector3f targetPoint = pieces.get(uuid).getLocation();
JetAnimation anim = new JetAnimation(app, rootNode, uuid, targetPoint, 40, 6, ()->throwPieceAnim(uuid));
anim.start();
}
private void throwMatrix(UUID uuid) {
//app.getAcousticHandler().playSound(MdgaSound.MATRIX);
Spatial piece = pieces.get(uuid).getSpatial();
piece.addControl(new MatrixAnimation(app, radarPos,()-> {
piece.addControl(new FadeControl(1,1,0,
() -> {
throwPiece(uuid);
piece.addControl(new FadeControl(1,0,1));
}
));
}));
}
private void throwMissle(UUID uuid) {
}
private void throwShell(UUID uuid) {
pieces.get(uuid).getSpatial().addControl(new ShellAnimation(tankTop, app, ()-> throwPieceAnim(uuid)));
}
/**

View File

@@ -7,6 +7,8 @@
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.FXAAFilter;
import com.jme3.post.ssao.SSAOFilter;
import com.jme3.scene.Spatial;
import com.jme3.shadow.DirectionalLightShadowFilter;
import com.jme3.shadow.EdgeFilteringMode;
@@ -37,6 +39,8 @@ public class CameraHandler {
private Color ownColor;
private boolean init;
private boolean initRot;
private SSAOFilter ssaoFilter;
private FXAAFilter fxaaFilter;
/**
* Constructor for the CameraHandler. Initializes the camera settings and lighting.
@@ -65,6 +69,9 @@ public CameraHandler(MdgaApp app, FilterPostProcessor fpp) {
dlsf.setEnabled(true);
dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
dlsf.setShadowIntensity(0.7f);
ssaoFilter = new SSAOFilter(6, 10f, 0.33f, 0.61f);
// ssaoFilter = new SSAOFilter();
fxaaFilter = new FXAAFilter();
sky = SkyFactory.createSky(app.getAssetManager(), "Images/sky/sky.dds", EnvMapType.EquirectMap).rotate(FastMath.HALF_PI*1,0,FastMath.HALF_PI*0.2f);
@@ -82,6 +89,8 @@ public void init(Color ownColor) {
app.getRootNode().addLight(ambient);
app.getRootNode().attachChild(sky);
fpp.addFilter(dlsf);
fpp.addFilter(ssaoFilter);
fpp.addFilter(fxaaFilter);
init = true;
initRot = true;
this.ownColor = ownColor;
@@ -93,15 +102,18 @@ public void init(Color ownColor) {
* and resets the camera position and rotation to its default state.
*/
public void shutdown() {
app.getRootNode().removeLight(sun);
app.getRootNode().removeLight(ambient);
init = false;
fpp.removeFilter(fxaaFilter);
fpp.removeFilter(ssaoFilter);
fpp.removeFilter(dlsf);
app.getRootNode().detachChild(sky);
app.getRootNode().removeLight(ambient);
app.getRootNode().removeLight(sun);
// Reset the camera to its default state
app.getCamera().setLocation(defaultCameraPosition);
app.getCamera().setRotation(defaultCameraRotation);
fpp.removeFilter(dlsf);
}
/**

View File

@@ -107,8 +107,11 @@ private static Asset getLoadedAsset(String assetName) {
case "radar" -> Asset.radar;
case "ship" -> Asset.ship;
case "tank" -> Asset.tank;
case "tree_small" -> Asset.treeSmall;
case "tree_big" -> Asset.treeBig;
case "treeSmall" -> Asset.treeSmall;
case "treeBig" -> Asset.treeBig;
case "tank_shoot" -> Asset.tankShoot;
case "treesBigBackground" -> Asset.treesBigBackground;
case "treesSmallBackground" -> Asset.treesSmallBackground;
default -> throw new IllegalStateException("Unexpected value: " + assetName);
};
}

View File

@@ -141,7 +141,7 @@ public void initSpatial(){
}
public void rotateInit() {
// rotate(rotation - initRotation);
setRotation(initRotation);
}
/**
@@ -278,4 +278,5 @@ public boolean isSelectable() {
public void setHoverable(boolean hoverable) {
this.hoverable = hoverable;
}
}

View File

@@ -0,0 +1,105 @@
package pp.mdga.client.board;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import pp.mdga.client.InitControl;
import static pp.mdga.client.Util.linInt;
public class TankTopControl extends InitControl {
private float timer = 0; // Time elapsed
private final static float DURATION = 1.5f; // Total rotation duration in seconds
private boolean rotating = false; // Flag to track if rotation is active
private float startAngle = 0;
private float endAngle = 0;
private Runnable actionAfter = null;
@Override
protected void controlUpdate(float tpf) {
if (!rotating) return;
// Update the timer
timer += tpf;
// Calculate interpolation factor (0 to 1)
float t = timer / DURATION;
if (t >= 1) t = 1;
float curAngle = linInt(startAngle, endAngle, t);
// Interpolate the rotation
Quaternion interpolatedRotation = new Quaternion();
interpolatedRotation.fromAngleAxis((float) Math.toRadians(curAngle), Vector3f.UNIT_Z);
// Apply the interpolated rotation to the spatial
spatial.setLocalRotation(interpolatedRotation);
if(t >= 1){
rotating = false;
if(actionAfter != null) actionAfter.run();
}
}
public void rotate(Vector3f enemyPos, Runnable actionAfter) {
if (spatial == null) throw new RuntimeException("spatial is null");
startAngle = getOwnAngle();
endAngle = getEnemyAngle(enemyPos);
// Adjust endAngle to ensure the shortest path
float deltaAngle = endAngle - startAngle;
if (deltaAngle > 180) {
endAngle -= 360; // Rotate counterclockwise
} else if (deltaAngle < -180) {
endAngle += 360; // Rotate clockwise
}
timer = 0;
rotating = true;
this.actionAfter = actionAfter; // Store the action to execute after rotation
}
private float getEnemyAngle(Vector3f enemyPos){
// Direction to the enemy in the XY plane
Vector3f direction = enemyPos.subtract(spatial.getLocalTranslation());
direction.z = 0; // Project to XY plane
direction.normalizeLocal();
Vector3f reference = Vector3f.UNIT_Y.mult(-1);
// Calculate the angle between the direction vector and the reference vector
float angle = FastMath.acos(reference.dot(direction));
// Determine rotation direction using the cross product
Vector3f cross = reference.cross(direction);
if (cross.z < 0) {
angle = -angle;
}
return (float) Math.toDegrees(angle); // Return the absolute angle in degrees
}
private float getOwnAngle() {
// Tank's forward direction in the XY plane
Vector3f forward = spatial.getLocalRotation().mult(Vector3f.UNIT_Y);
forward.z = 0; // Project to XY plane
forward.normalizeLocal();
// Reference vector: Positive X-axis
Vector3f reference = Vector3f.UNIT_Y;
// Calculate the angle between the forward vector and the reference vector
float angle = FastMath.acos(reference.dot(forward));
// Determine rotation direction using the cross product
Vector3f cross = reference.cross(forward);
if (cross.z < 0) { // For Z-up, check the Z component of the cross product
angle = -angle;
}
return (float) Math.toDegrees(angle); // Return the absolute angle in radians
}
}

View File

@@ -1,4 +1,43 @@
package pp.mdga.client.dialog;
public class InterruptDialog {
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.AbstractButton;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.LabelButton;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MdgaView;
public class InterruptDialog extends Dialog {
private ButtonRight forceButton;
private LabelButton label;
public InterruptDialog(MdgaApp app, Node node) {
super(app, node);
forceButton = new ButtonRight(app, node, () -> app.getModelSynchronize().force(), "Erzwingen", 1);
label = new LabelButton(app, node, "Warte auf Spieler...", new Vector2f(5.5f * 1.5f, 2), new Vector2f(0.5f, 0f), false);
float offset = 2.8f;
label.setPos(new Vector2f(0, MenuButton.VERTICAL - offset));
}
@Override
protected void onShow() {
if(app.getGameLogic().isHost()) {
forceButton.show();
}
label.show();
}
@Override
protected void onHide() {
forceButton.hide();
label.hide();
}
}

View File

@@ -92,4 +92,16 @@ public void resetPort() {
public void connectToServer() {
connectServer();
}
public void disconnect() {
NetworkSupport network = getNetwork();
if (network != null) {
try {
network.disconnect();
} catch (Exception e) {
System.err.println("Error while disconnecting: " + e.getMessage());
}
}
}
}

View File

@@ -14,6 +14,8 @@ public abstract class NetworkDialog extends Dialog {
private String hostname;
private int portNumber;
private Future<Object> connectionFuture;
private MdgaServer serverInstance;
private Thread serverThread;
public NetworkDialog(MdgaApp app, Node node, NetworkSupport network) {
super(app, node);
@@ -28,7 +30,6 @@ public void setPortNumber(int portNumber) {
this.portNumber = portNumber;
}
protected Object initNetwork() {
try {
this.network.initNetwork(this.hostname, this.portNumber);
@@ -39,25 +40,49 @@ protected Object initNetwork() {
}
protected void connectServer() {
try {
connectionFuture = this.network.getApp().getExecutor().submit(this::initNetwork);
} catch (NumberFormatException var2) {
throw new NumberFormatException("Port must be a number");
}
}
protected void startServer() {
(new Thread(() -> {
serverThread = new Thread(() -> {
try {
MdgaServer mdgaServer = new MdgaServer(portNumber);
mdgaServer.run();
serverInstance = new MdgaServer(portNumber);
serverInstance.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
})).start();
serverThread.start();
}
public void shutdownServer() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Thread was interrupted: " + e.getMessage());
}
if (serverInstance != null) {
serverInstance.shutdown();
serverInstance = null;
}
if (serverThread != null && serverThread.isAlive()) {
serverThread.interrupt();
try {
serverThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
serverThread = null;
}
}
public void update(float delta) {
@@ -65,14 +90,14 @@ public void update(float delta) {
try {
this.connectionFuture.get();
} catch (ExecutionException ignored) {
// todo: implement
// TODO: implement
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public NetworkSupport getNetwork(){
public NetworkSupport getNetwork() {
return network;
}
}

View File

@@ -177,6 +177,109 @@ public String getName() {
"CarryPro",
"ProBaiter",
"GameWarden",
"KartoffelKönig",
"SaufenderWolf",
"WurstGriller",
"Flitzekacke",
"BratwurstBub",
"Hoppeldoppels",
"BananenMensch",
"KlopapierGuru",
"SchnitzelKing",
"NerdNomade",
"Dönertänzer",
"GlitzerGurke",
"SchinkenShrek",
"KäseKalle",
"SchokoSchnecke",
"KeksKämpfer",
"QuarkPiraten",
"Müslimonster",
"KnuddelNase",
"FantaFighter",
"SchnapsSaurier",
"Wackelpudding",
"ZitronenZock",
"FettWurst",
"PlüschPanda",
"Zuckerschnur",
"FluffiKopf",
"DonutDöner",
"VollpfostenX",
"Schraubenschlüssel",
"Witzepumper",
"ToastTraum",
"FroschFighter",
"KrümelTiger",
"RegenWolke",
"PuddingPower",
"KoffeinKrieger",
"SpeckSchlumpf",
"SuperSuppe",
"BierBärchen",
"FischBär",
"Flauschi",
"Schokomonster",
"ChaosKäse",
"FlitzLappen",
"WurstWombat",
"KrümelMensch",
"PuddingBär",
"ZickZack",
"Schwabel",
"Fluffi",
"RülpsFrosch",
"PommesPapa",
"QuarkBär",
"KnusperKönig",
"ToastBrot",
"Ploppster",
"Schleimschwein",
"Äpfelchen",
"Knallbonbon",
"KaffeeKopf",
"WackelWurst",
"RennKeks",
"BröselBub",
"ZockerBrot",
"BierWurm",
"StinkFlummi",
"SchlumpfKing",
"PurzelBär",
"FlinkFluff",
"PloppPudel",
"Schnorchel",
"FliegenKopf",
"PixelPommes",
"SchwipsWürst",
"WutzBär",
"KnuddelKeks",
"FantaFlumm",
"ZockerKäse",
"LachHäufchen",
"GurkenGuru",
"PonySchnitzel",
"NudelNinja",
"VulkanKeks",
"WasserToast",
"MenschSalat",
"KampfKohlenhydrate",
"SockenZirkus",
"SchwimmBärchen",
"TanzenderDachgepäckträger",
"PizzamarktMensch",
"ZahnarztZocker",
"RollerCoasterTester",
"WaschmaschinenPilot",
"WitzigeZwiebel",
"Pillenschlucker",
"ZwiebelReiter",
"HüpfenderKaktus",
"KochenderAsteroid",
"ChaosKarotte",
"WolkenFurz",
"SchnitzelPartikel",
"WackelBiene",
};
Random random = new Random();

View File

@@ -3,13 +3,20 @@
import com.jme3.math.Vector2f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.AbstractButton;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.button.MenuButton;
import pp.mdga.client.view.MdgaView;
import java.util.prefs.Preferences;
public class VideoSettingsDialog extends Dialog {
private static Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
private ButtonRight fullscreenButton;
private MenuButton backButton;
private ButtonRight restartButton;
private ButtonLeft hdButton9;
private ButtonLeft fullHdButton9;
@@ -29,20 +36,24 @@ public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) {
backButton = new MenuButton(app, node, view::leaveVideoSettings, "Zurück");
// MenuButton für verschiedene Auflösungen erstellen
hdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(1280, 720, 1.0f), "hd 16:9", 10);
fullHdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(1920, 1080, 2.25f), "full hd 16:9", 10);
wqhdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(2560, 1440, 4.0f), "wqhd 16:9", 10);
restartButton = new ButtonRight(app, node, MdgaApp::restartApp, "Neustart", 1);
fullscreenButton = new ButtonRight(app, node, () -> updateResolution(0, 0, 0, true), "Vollbild", 1);
hdButton9 = new ButtonLeft(app, node, () -> updateResolution(1280, 720, 1.0f, false), "hd 16:9", 10);
fullHdButton9 = new ButtonLeft(app, node, () -> updateResolution(1920, 1080, 2.25f, false), "full hd 16:9", 10);
wqhdButton9 = new ButtonLeft(app, node, () -> updateResolution(2560, 1440, 4.0f, false), "wqhd 16:9", 10);
hdButton10 = new ButtonRight(app, node, () -> app.updateResolution(1280, 800, 1.0f), "hd 16:10", 10);
fullHdButton10 = new ButtonRight(app, node, () -> app.updateResolution(1920, 1200, 2.25f), "full hd 16:10", 10);
wqhdButton10 = new ButtonRight(app, node, () -> app.updateResolution(2560, 1600, 4.0f), "wqhd 16:10", 10);
hdButton10 = new ButtonRight(app, node, () -> updateResolution(1280, 800, 1.0f, false), "hd 16:10", 10);
fullHdButton10 = new ButtonRight(app, node, () -> updateResolution(1920, 1200, 2.25f, false), "full hd 16:10", 10);
wqhdButton10 = new ButtonRight(app, node, () -> updateResolution(2560, 1600, 4.0f, false), "wqhd 16:10", 10);
float offset = 2.8f;
hdButton9.setPos(new Vector2f(hdButton9.getPos().x, MenuButton.VERTICAL - offset));
hdButton10.setPos(new Vector2f(hdButton10.getPos().x, MenuButton.VERTICAL - offset));
fullscreenButton.setPos(new Vector2f(fullscreenButton.getPos().x, MenuButton.VERTICAL - offset));
offset += 1.5f;
fullHdButton9.setPos(new Vector2f(fullHdButton9.getPos().x, MenuButton.VERTICAL - offset));
@@ -68,6 +79,7 @@ protected void onShow() {
fullHdButton10.show();
wqhdButton10.show();
fullscreenButton.show();
backButton.show();
}
@@ -83,7 +95,9 @@ protected void onHide() {
fullHdButton10.hide();
wqhdButton10.hide();
fullscreenButton.hide();
backButton.hide();
restartButton.hide();
}
public void update() {
@@ -91,4 +105,12 @@ public void update() {
return;
}
}
public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) {
if(width != prefs.getInt("width", 1280) || height != prefs.getInt("height", 720) || isFullscreen != prefs.getBoolean("fullscreen", false)) {
restartButton.show();
}
app.updateResolution(width, height, imageFactor, isFullscreen);
}
}

View File

@@ -152,5 +152,4 @@ void rollRankingResultOwn(Color color, int eye){
void diceNow(){
createTopText("Klicke zum Würfeln", 5, 80, ColorRGBA.White, 0);
}
}

View File

@@ -60,7 +60,7 @@ private Node createNum(){
Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Black);
circle.setMaterial(mat);
root.attachChild(circle);
// root.attachChild(circle);
BitmapFont guiFont = getApp().getAssetManager().loadFont("Fonts/Gunplay.fnt");
num = new BitmapText(guiFont);
num.setSize(0.3f);

View File

@@ -8,6 +8,7 @@
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.ComposeFilter;
import com.jme3.post.filters.FXAAFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
@@ -31,35 +32,46 @@ public class CardLayer extends AbstractAppState {
private List<Spatial> cardBuffer;
private final FilterPostProcessor fpp;
private final Camera overlayCam;
Texture2D backTexture;
private Texture2D backTexture;
private FXAAFilter fxaaFilter;
private ViewPort view;
private DirectionalLightShadowFilter dlsf;
DirectionalLight sun;
ComposeFilter compose;
public CardLayer(FilterPostProcessor fpp, Camera overlayCam, Texture2D backTexture) {
this.overlayCam = overlayCam;
this.fpp = fpp;
this.cardBuffer = new ArrayList<>();
init = false;
this.backTexture = backTexture;
cardBuffer = new ArrayList<>();
init = false;
fxaaFilter = new FXAAFilter();
view = null;
dlsf = null;
sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(.5f, -.5f, -1));
compose = new ComposeFilter(backTexture);
root = new Node("Under gui viewport Root");
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
this.app = app;
root = new Node("Under gui viewport Root");
ViewPort view = app.getRenderManager().createMainView("Under gui ViewPort", overlayCam);
view = app.getRenderManager().createMainView("Under gui ViewPort", overlayCam);
view.setEnabled(true);
view.setClearFlags(true, true, true);
view.attachScene(root);
fpp.setFrameBufferFormat(Image.Format.RGBA8);
fpp.addFilter(new ComposeFilter(backTexture));
fpp.addFilter(compose);
fpp.addFilter(fxaaFilter);
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(.5f, -.5f, -1));
root.addLight(sun);
DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(app.getAssetManager(), SHADOWMAP_SIZE, 3);
dlsf = new DirectionalLightShadowFilter(app.getAssetManager(), SHADOWMAP_SIZE, 3);
dlsf.setLight(sun);
dlsf.setEnabled(true);
dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
@@ -72,6 +84,15 @@ public void initialize(AppStateManager stateManager, Application app) {
}
public void shutdown() {
view.clearProcessors();
fpp.removeFilter(dlsf);
dlsf = null;
root.removeLight(sun);
fpp.removeFilter(fxaaFilter);
fpp.removeFilter(compose);
view.detachScene(root);
app.getRenderManager().removeMainView(view);
cardBuffer.clear();
root.detachAllChildren();
}
@@ -94,7 +115,8 @@ public void update(float tpf) {
}
public void addSpatial(Spatial card) {
cardBuffer.add(card);
if(root == null) cardBuffer.add(card);
else root.attachChild(card);
}
public void deleteSpatial(Spatial spatial) {

View File

@@ -85,6 +85,19 @@ public void addCard(BonusCard card) {
bonusCardControlMap.get(card).setNumCard(newNum);
}
public void removeCard(BonusCard card){
if(bonusCardControlMap.containsKey(card)){
bonusCardIntegerMap.put(card, bonusCardIntegerMap.get(card) - 1);
if(bonusCardIntegerMap.get(card) <= 0){
cardLayer.deleteSpatial(bonusCardControlMap.get(card).getRoot());
bonusCardIntegerMap.remove(card);
bonusCardControlMap.remove(card);
}
}
}
public void clearSelectableCards() {
for (CardControl control : selectableCards) {
control.setSelectable(false);

View File

@@ -39,14 +39,15 @@ public DiceControl(AssetManager assetManager){
@Override
protected void controlUpdate(float tpf) {
float clampedTpf = Math.min(tpf, 0.05f); // Max 50 ms per frame
if (isRolling) {
if(!slerp) {
// Apply rotational velocity to the dice
spinWithAngularVelocity(tpf);
spinWithAngularVelocity(clampedTpf);
// Gradually reduce rotational velocity (simulate deceleration)
angularVelocity.subtractLocal(
angularVelocity.mult(deceleration * tpf)
angularVelocity.mult(deceleration * clampedTpf)
);
// Stop rolling when angular velocity is close to zero
@@ -55,7 +56,7 @@ protected void controlUpdate(float tpf) {
}
}
else {
timeElapsed += tpf * rollDuration;
timeElapsed += clampedTpf * rollDuration;
if (timeElapsed > 1.0f) timeElapsed = 1.0f;
@@ -71,7 +72,7 @@ protected void controlUpdate(float tpf) {
}
}
}else if(spin){
spinWithAngularVelocity(tpf);
spinWithAngularVelocity(clampedTpf);
}
}

View File

@@ -74,8 +74,31 @@ public void hideDice() {
cardLayerHandler.hideDice();
}
public void addCard(BonusCard card) {
//add own handCard
public void addCardOwn(BonusCard card) {
cardLayerHandler.addCard(card);
playerNameHandler.addCard(ownColor);
actionTextHandler.drawCardOwn(ownColor);
}
public void playCardOwn(BonusCard card){
getEffectByCard(card);
cardLayerHandler.removeCard(card);
playerNameHandler.removeCard(ownColor);
}
public void playCardEnemy(Color color, BonusCard card) {
getEffectByCard(card);
playerNameHandler.removeCard(color);
}
private void getEffectByCard(BonusCard bonus){
switch(bonus){
case SWAP -> swap();
case TURBO -> turbo();
case SHIELD -> shield();
default -> throw new RuntimeException("invalid card");
}
}
public void clearSelectableCards() {
@@ -125,9 +148,11 @@ public void hideText(){
actionTextHandler.hide();
}
//addCard Enemy (DrawCardNotification)
public void drawCard(Color color) {
if (ownColor == color) actionTextHandler.drawCardOwn(color);
else actionTextHandler.drawCard(playerNameHandler.getName(color), color);
//Color != ownColor
actionTextHandler.drawCard(playerNameHandler.getName(color), color);
playerNameHandler.addCard(color);
}
public void finish(Color color){
@@ -141,4 +166,6 @@ public void rollRankingResult(Color color, int eye){
}
}

View File

@@ -4,23 +4,27 @@
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.system.AppSettings;
import com.jme3.ui.Picture;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
public class PlayerNameHandler {
private final BitmapFont playerFont;
private final Node playerNameNode;
private final List<Color> playerOrder;
private final Map<Color, String> colorNameMap;
private final Map<Color, Integer> colorCardMap;
private final AppSettings appSettings;
private final AssetManager assetManager;
private Color ownColor;
@@ -43,6 +47,7 @@ public PlayerNameHandler(Node guiNode, AssetManager assetManager, AppSettings ap
playerNameNode = new Node("player name node");
playerOrder = new ArrayList<>();
colorNameMap = new HashMap<>();
colorCardMap = new HashMap<>();
this.appSettings = appSettings;
this.assetManager = assetManager;
}
@@ -64,13 +69,38 @@ private void drawPlayers(){
if(!colorNameMap.containsKey(color)) throw new RuntimeException(color + " isn't mapped to a name");
Node nameParent = new Node("nameParent");
nameParent.attachChild(createName(colorNameMap.get(color), i == 0, color == ownColor));
nameParent.attachChild(createColor(color));
BitmapText name = createName(colorNameMap.get(color), i == 0, color == ownColor);
nameParent.attachChild(name);
if(colorCardMap.getOrDefault(color, 0) > 0){
Picture pic = createHandCard(name.getLineWidth());
nameParent.attachChild(pic);
nameParent.attachChild(createCardNum(colorCardMap.get(color), pic.getWidth(), pic.getLocalTranslation().getX()));
}
nameParent.setLocalTranslation(50,appSettings.getWindowHeight()-PADDING_TOP- MARGIN_NAMES *i,0);
playerNameNode.attachChild(nameParent);
}
}
private Spatial createCardNum(int num, float lastWidth, float lastX ) {
BitmapText hudText = new BitmapText(playerFont);
//renderedSize = 45
hudText.setSize(TEXT_SIZE);
hudText.setColor(NORMAL_COLOR);
hudText.setText(String.valueOf(num));
hudText.setLocalTranslation(lastX + lastWidth + 20,hudText.getHeight()/2, 0);
return hudText;
}
private Picture createHandCard(float width) {
Picture pic = new Picture("HUD Picture");
pic.setImage(assetManager, "./Images/handcard.png", true);
pic.setWidth(IMAGE_SIZE);
pic.setHeight(IMAGE_SIZE);
pic.setPosition(-pic.getWidth()/2 + width + PADDING_LEFT * 2 ,-pic.getHeight()/2);
return pic;
}
private String imagePath(Color color){
String root = "./Images/name_pictures/";
return switch(color){
@@ -93,7 +123,7 @@ private Spatial createColor(Color color) {
private Spatial createName(String name, boolean first, boolean own){
private BitmapText createName(String name, boolean first, boolean own){
BitmapText hudText = new BitmapText(playerFont);
//renderedSize = 45
hudText.setSize(TEXT_SIZE);
@@ -124,5 +154,18 @@ public String getName(Color color){
return colorNameMap.get(color);
}
public void addCard(Color color){
colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) + 1);
drawPlayers();
}
public void removeCard(Color color){
if(colorCardMap.containsKey(color)){
colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) - 1);
if(colorCardMap.get(color) <= 0) colorCardMap.remove(color);
}
drawPlayers();
}
}

View File

@@ -3,6 +3,7 @@
import com.jme3.asset.AssetManager;
import com.jme3.math.ColorRGBA;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.FXAAFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
@@ -54,7 +55,6 @@ public void select(Spatial model, ColorRGBA color, int width) {
}
private void hideOutlineFilterEffect(Spatial model) {
// app.enqueue(() -> {
outlineFilter.setEnabled(false);
outlineFilter.getOutlinePreFilter().setEnabled(false);
fpp.removeFilter(outlineFilter);
@@ -62,18 +62,14 @@ private void hideOutlineFilterEffect(Spatial model) {
outlineViewport.clearProcessors();
renderManager.removePreView(outlineViewport);
outlineViewport = null;
// return null;
// });
}
private void showOutlineFilterEffect(Spatial model, int width, ColorRGBA color) {
// app.enqueue(() -> {
outlineViewport = renderManager.createPreView("outlineViewport", cam);
FilterPostProcessor outlineFpp = new FilterPostProcessor(assetManager);
OutlinePreFilter outlinePreFilter = new OutlinePreFilter();
outlineFpp.addFilter(outlinePreFilter);
outlineViewport.attachScene(model);
outlineViewport.addProcessor(outlineFpp);
@@ -82,7 +78,5 @@ private void showOutlineFilterEffect(Spatial model, int width, ColorRGBA color)
outlineFilter.setOutlineWidth(width);
fpp.addFilter(outlineFilter);
// return null;
// });
}
}

View File

@@ -3,6 +3,7 @@
import com.jme3.network.*;
import com.jme3.network.serializing.Serializer;
import com.jme3.network.serializing.serializers.EnumSerializer;
import pp.mdga.Resources;
import pp.mdga.game.*;
import pp.mdga.message.client.*;
import pp.mdga.message.server.*;
@@ -135,6 +136,7 @@ private void initializeSerializables() {
Serializer.registerClass(UpdateReadyMessage.class);
Serializer.registerClass(UpdateTSKMessage.class);
Serializer.registerClass(WaitPieceMessage.class);
Serializer.registerClass(IncorrectRequestMessage.class);
Serializer.registerClass(Player.class);
Serializer.registerClass(Statistic.class);
Serializer.registerClass(Board.class);
@@ -144,8 +146,10 @@ private void initializeSerializables() {
Serializer.registerClass(StartNode.class);
Serializer.registerClass(PlayerData.class);
Serializer.registerClass(HomeNode.class);
Serializer.registerClass(PlayerDataMessage.class);
Serializer.registerClass(StartBriefingMessage.class);
Serializer.registerClass(Color.class, new EnumSerializer());
Serializer.registerClass(PieceState.class, new EnumSerializer());
Serializer.registerClass(ShieldState.class, new EnumSerializer());
}
private void registerListeners() {
@@ -198,12 +202,31 @@ private void messageReceived(HostedConnection source, ClientMessage message) {
pendingMessages.add(new ReceivedMessage(message, source.getId()));
}
/**
* This method will be used to handle all connections which are connected to the server.
* It will check if the maximum number of connected clients are already reached. If yes it will send a
* LobbyDenyMessage to the given hostedConnection parameter and close it, otherwise it will send a
* LobbyAcceptMessage to the given hostedConnection parameter. In Addition, if the number of connected clients is
* equal to 1 it will set the host of the game to the id of the given hostedConnection parameter.
*
* @param server as the server which is contains all connections as a Server object.
* @param hostedConnection as the connection which is added to the server as a HostedConnection object.
*/
@Override
public void connectionAdded(Server server, HostedConnection hostedConnection) {
System.out.println("new connection " + hostedConnection); //NON-NLS
LOGGER.log(Level.DEBUG, "new connection {0}", hostedConnection); //NON-NLS
if (this.myServer.getConnections().size() == 1) {
this.logic.getGame().setHost(hostedConnection.getId());
if (this.myServer.getConnections().size() > Resources.MAX_PLAYERS) {
this.logic.getServerSender().send(hostedConnection.getId(), new LobbyDenyMessage());
hostedConnection.close("");
} else {
if (hostedConnection.getAddress().contains("127.0.0.1") && this.logic.getGame().getHost() == -1) {
this.logic.getGame().setHost(hostedConnection.getId());
this.logic.getServerSender().send(hostedConnection.getId(), new LobbyAcceptMessage(hostedConnection.getId()));
} else {
this.logic.getServerSender().send(hostedConnection.getId(), new LobbyAcceptMessage());
}
}
}
@@ -278,4 +301,21 @@ public void broadcast(ServerMessage message) {
public void disconnectClient(int id) {
this.myServer.getConnection(id).close("");
}
/**
* This method will be used to shut down the server.
* It will iterate threw all connections of myServer attribute and check if they are equal to null. If not they will
* be closed. After that the myServer attribute will be closed and this program will be exited with the exit code 0.
*/
@Override
public void shutdown() {
for (HostedConnection client : this.myServer.getConnections()) {
if (client != null) {
client.close("Host closed the server.");
}
}
this.myServer.close();
this.exit(0);
}
}

View File

@@ -206,11 +206,19 @@ public void addCeremonyParticipant(Color color, int pos, String name) {
ceremonyButtons.add(button);
if(state.equals(SubState.AWARD_CEREMONY)) {
button.hide();
button.show();
}
}
public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) {
ceremonyDialog.addStatisticsRow(name, v1, v2, v3, v4, v5, v6);
ceremonyDialog.hide();
ceremonyDialog.show();
}
public void afterGameCleanup() {
ceremonyDialog.prepare();
}
}

View File

@@ -1,31 +1,16 @@
package pp.mdga.client.view;
import com.jme3.post.FilterPostProcessor;
import pp.mdga.client.MdgaState;
import com.jme3.scene.Node;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.board.CameraHandler;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.button.ButtonLeft;
import pp.mdga.client.button.ButtonRight;
import pp.mdga.client.dialog.InterruptDialog;
import pp.mdga.client.gui.GuiHandler;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import pp.mdga.notification.AcquireCardNotification;
import pp.mdga.notification.ActivePlayerNotification;
import pp.mdga.notification.DiceNowNotification;
import pp.mdga.notification.GameNotification;
import pp.mdga.notification.MovePieceNotification;
import pp.mdga.notification.PlayerInGameNotification;
import pp.mdga.notification.RollDiceNotification;
import pp.mdga.notification.SelectableCardsNotification;
import pp.mdga.notification.SelectableMoveNotification;
import pp.mdga.notification.SelectableSwapNotification;
import pp.mdga.notification.ShieldActiveNotification;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class GameView extends MdgaView {
private BoardHandler boardHandler;
@@ -37,26 +22,32 @@ public class GameView extends MdgaView {
private Color ownColor = null;
private InterruptDialog interruptDialog;
private FilterPostProcessor fpp;
private Node guiHandlerNode = new Node();
public GameView(MdgaApp app) {
super(app);
leaveButton = new ButtonLeft(app, overlayNode, () -> app.getModelSynchronize().leave(), "Spiel verlassen", 1);
leaveButton = new ButtonLeft(app, settingsNode, () -> app.getModelSynchronize().leave(), "Spiel verlassen", 1);
confirmButton = new ButtonRight(app, guiNode, () -> app.getModelSynchronize().confirm(), "Bestätigen", 1);
interruptDialog = new InterruptDialog(app, guiNode);
fpp = new FilterPostProcessor(app.getAssetManager());
this.camera = new CameraHandler(app, fpp);
this.boardHandler = new BoardHandler(app, rootNode, fpp);
guiHandler = new GuiHandler(app, guiNode);
guiHandler = new GuiHandler(app, guiHandlerNode);
guiNode.attachChild(guiHandlerNode);
}
@Override
public void onEnter() {
setOwnColor(Color.AIRFORCE);
camera.init(ownColor);
boardHandler.init();
guiHandler.init(ownColor);
@@ -64,13 +55,6 @@ public void onEnter() {
app.getViewPort().addProcessor(fpp);
app.getAcousticHandler().playSound(MdgaSound.START);
// guiHandler.addPlayer(Color.AIRFORCE, "Cedric");
// guiHandler.addPlayer(Color.ARMY, "Ben");
// guiHandler.addPlayer(Color.CYBER, "Felix");
// guiHandler.addPlayer(Color.NAVY, "Daniel");
}
@Override
@@ -131,4 +115,26 @@ public void needConfirm() {
public void noConfirm() {
confirmButton.hide();
}
public void enterInterrupt() {
enterOverlay(Overlay.INTERRUPT);
guiNode.detachChild(guiHandlerNode);
app.getGuiNode().attachChild(guiNode);
app.getInputSynchronize().setClickAllowed(false);
interruptDialog.show();
}
public void leaveInterrupt() {
leaveOverlay(Overlay.INTERRUPT);
app.getGuiNode().detachChild(guiNode);
guiNode.attachChild(guiHandlerNode);
app.getInputSynchronize().setClickAllowed(true);
interruptDialog.hide();
}
}

View File

@@ -18,6 +18,7 @@
import pp.mdga.client.button.LobbyButton;
import pp.mdga.client.button.SettingsButton;
import pp.mdga.game.Color;
import pp.mdga.message.client.StartGameMessage;
import pp.mdga.notification.GameNotification;
public class LobbyView extends MdgaView {
@@ -25,6 +26,7 @@ public class LobbyView extends MdgaView {
private ButtonLeft leaveButton;
private ButtonRight readyButton;
private ButtonRight startButton;
private LobbyButton cyberButton;
private LobbyButton airforceButton;
@@ -42,6 +44,7 @@ public LobbyView(MdgaApp app) {
leaveButton = new ButtonLeft(app, guiNode, this::leaveLobby, "Verlassen", 1);
readyButton = new ButtonRight(app, guiNode, this::ready, "Bereit", 1);
startButton = new ButtonRight(app, guiNode, () -> app.getGameLogic().selectStart(), "Starten", 7);
cyberButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.CYBER), Color.CYBER);
airforceButton = new LobbyButton(app, guiNode, rootNode, () -> toggleTsk(Color.AIRFORCE), Color.AIRFORCE);
@@ -61,6 +64,10 @@ public void onEnter() {
leaveButton.show();
readyButton.show();
if(app.getGameLogic().isHost()) {
startButton.show();
}
cyberButton.show();
airforceButton.show();
armyButton.show();
@@ -95,6 +102,7 @@ public void onEnter() {
public void onLeave() {
leaveButton.hide();
readyButton.hide();
startButton.hide();
airforceButton.hide();
armyButton.hide();
@@ -223,6 +231,10 @@ private void toggleTsk(Color color) {
break;
}
if(isReady) {
setReady(own, false);
}
switch (taken) {
case NOT:
app.getModelSynchronize().selectTsk(color);

View File

@@ -7,9 +7,6 @@
import pp.mdga.client.dialog.JoinDialog;
import pp.mdga.client.dialog.StartDialog;
import java.net.Inet4Address;
import java.net.UnknownHostException;
public class MainView extends MdgaView {
private enum SubState {
HOST,
@@ -63,12 +60,12 @@ public void onUpdate(float tpf) {
@Override
protected void onEnterOverlay(Overlay overlay) {
guiNode.detachChild(background);
overlayNode.attachChild(background);
settingsNode.attachChild(background);
}
@Override
protected void onLeaveOverlay(Overlay overlay) {
overlayNode.detachChild(background);
settingsNode.detachChild(background);
guiNode.attachChild(background);
}
@@ -96,6 +93,7 @@ private void mainMenu() {
private void tryHost() {
int port = 0;
String text = hostDialog.getPort();
app.getGameLogic().selectHost("");
try {
port = Integer.parseInt(text);
@@ -108,10 +106,6 @@ private void tryHost() {
} catch (InterruptedException ignored) {
}
hostDialog.connectServerAsClient();
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
app.getModelSynchronize().setHost(port);
//app.getAcousticHandler().playSound(MdgaSound.WRONG_INPUT);
return;
@@ -127,6 +121,7 @@ private void tryJoin() {
int port = 0;
String ip = joinDialog.getIpt();
String portText = joinDialog.getPort();
app.getGameLogic().selectJoin("");
try {
// Validate the port
@@ -140,11 +135,6 @@ private void tryJoin() {
app.getModelSynchronize().setName(startDialog.getName());
joinDialog.setHostname(ip);
joinDialog.connectToServer();
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
app.getModelSynchronize().setJoin(ip, port);
return;
}
} catch (IllegalArgumentException e) {
@@ -234,5 +224,13 @@ public void back() {
break;
}
}
public JoinDialog getJoinDialog() {
return joinDialog;
}
public HostDialog getHostDialog() {
return hostDialog;
}
}

View File

@@ -2,9 +2,12 @@
import com.jme3.asset.TextureKey;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.system.NanoTimer;
import com.jme3.texture.Texture;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.acoustic.MdgaSound;
@@ -22,7 +25,7 @@ public enum Overlay {
protected MdgaApp app;
protected Node rootNode = new Node("View Root");
protected Node guiNode = new Node("View Root GUI");
protected Node overlayNode = new Node("View Root Overlay");
protected Node settingsNode = new Node("View Root Overlay");
private SettingsButton settingsButton;
@@ -30,15 +33,18 @@ public enum Overlay {
private VideoSettingsDialog videoSettingsDialog;
private AudioSettingsDialog audioSettingsDialog;
protected LabelButton infoLabel = null;
protected NanoTimer infoTimer = new NanoTimer();
private int settingsDepth = 0;
public MdgaView(MdgaApp app) {
this.app = app;
settingsButton = new SettingsButton(app, guiNode, this::enterSettings);
settingsDialog = new SettingsDialog(app, overlayNode, this);
videoSettingsDialog = new VideoSettingsDialog(app, overlayNode, this);
audioSettingsDialog = new AudioSettingsDialog(app, overlayNode, this);
settingsDialog = new SettingsDialog(app, settingsNode, this);
videoSettingsDialog = new VideoSettingsDialog(app, settingsNode, this);
audioSettingsDialog = new AudioSettingsDialog(app, settingsNode, this);
}
public void enter() {
@@ -80,6 +86,11 @@ public void update(float tpf) {
videoSettingsDialog.update();
audioSettingsDialog.update();
if (null != infoLabel && infoTimer.getTimeInSeconds() > 5) {
infoLabel.hide();
infoLabel = null;
}
onUpdate(tpf);
}
@@ -113,7 +124,7 @@ protected Geometry createBackground(String texturePath) {
public void enterSettings() {
enterOverlay(Overlay.SETTINGS);
app.getGuiNode().attachChild(overlayNode);
app.getGuiNode().attachChild(settingsNode);
settingsDialog.show();
@@ -123,7 +134,7 @@ public void enterSettings() {
public void leaveSettings() {
leaveOverlay(Overlay.SETTINGS);
app.getGuiNode().detachChild(overlayNode);
app.getGuiNode().detachChild(settingsNode);
settingsDialog.hide();
@@ -193,4 +204,24 @@ public void pressForward() {
ceremonyView.forward();
}
}
public void showInfo(String error, boolean isError) {
infoTimer.reset();
if(null != infoLabel) {
infoLabel.hide();
}
infoLabel = new LabelButton(app, guiNode, error, new Vector2f(5.5f, 2), new Vector2f(0.5f, AbstractButton.VERTICAL - 0.5f), false);
ColorRGBA color;
if(isError) {
color = ColorRGBA.Red.clone();
} else {
color = ColorRGBA.Green.clone();
}
infoLabel.setColor(ColorRGBA.Black, color);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,7 +1,7 @@
world 0,0 90
treesBigBackground 0,0 90
treesSmallBackground 0,0 90
#tree_small 1,1 0
#tree_big 0,0 0
#Marine Pos
marine 4,-5 270
@@ -58,7 +58,8 @@ big_tent -10,-9 130
big_tent 9,-10 225
radar 0,10 -20
tank -1,-10 135
tank 0,-18 180
#tank 0,-18 180
tank_shoot 0,-18 180
tank 3,-18 180
tank -3,-18 180
@@ -131,3 +132,145 @@ node_home_blue 4,0 0
node_home_blue 3,0 0
node_home_blue 2,0 0
node_home_blue 1,0 0
# Randomly Distributed Trees within Radius 12 to 40
treeSmall 10,15 180
treeBig -15,12 45
treeSmall -8,-22 270
treeBig 22,8 90
treeSmall -18,-10 135
treeBig 9,24 300
treeSmall 17,-9 60
treeBig -20,5 330
treeSmall -14,18 200
treeBig 25,-7 120
treeBig -12,-18 150
treeSmall 19,-16 45
treeBig 7,10 90
treeBig -19,-9 270
treeSmall 21,4 110
treeBig -11,17 300
treeSmall 3,-21 360
treeSmall -23,14 100
treeBig 4,26 330
treeSmall 12,13 270
treeBig -18,8 45
treeBig 11,-10 135
treeSmall 16,5 180
treeBig -13,-17 330
treeSmall -2,14 270
#treeBig 7,9 300
treeSmall 23,-10 240
treeBig -6,18 180
treeSmall 5,27 270
treeBig 14,-11 60
treeSmall 9,-16 180
treeBig -12,22 240
treeBig 18,7 360
treeSmall -24,-4 200
treeBig -8,21 300
treeSmall 12,-19 120
treeBig 6,-12 180
treeSmall -11,10 75
treeBig 9,6 270
treeSmall 8,-14 150
treeBig 3,18 30
treeSmall 17,13 100
treeBig -9,20 90
treeBig 6,-22 330
treeSmall -20,7 45
treeBig 21,11 150
treeSmall 15,-18 270
treeBig -3,-12 200
treeBig 12,-28 330
treeSmall -17,-7 120
treeBig -10,9 300
treeSmall 2,-14 240
treeBig 24,2 360
treeSmall 4,-13 300
treeBig -19,20 90
#treeSmall -11,5 45
treeBig 15,9 180
treeSmall -6,10 240
treeBig 3,15 30
treeSmall 9,-19 150
treeBig -21,-4 330
treeSmall 19,11 270
treeSmall 12,24 110
treeBig -13,15 45
treeSmall 7,-15 240
treeBig 26,-8 300
treeSmall -16,14 120
treeBig 14,18 360
treeSmall 8,21 100
treeBig -8,-18 240
treeSmall 9,15 180
treeBig 10,-20 270
treeSmall 2,27 90
treeBig 18,12 300
treeSmall -10,-14 150
treeBig -15,16 330
treeSmall -9,19 45
treeBig 17,-14 120
treeSmall 5,-25 180
treeBig 7,23 30
treeSmall -14,-12 200
treeBig 6,-16 300
treeSmall -20,-8 100
treeBig 4,11 240
treeSmall 24,-15 90
treeSmall -19,-19 360
treeBig 20,8 45
treeSmall 3,22 270
treeBig 13,-9 180
treeSmall -11,18 150
treeBig -17,-4 300
treeSmall 5,-14 240
treeBig 9,17 330
treeSmall 15,13 90
treeBig -21,18 30
treeSmall 6,20 100
treeBig -16,22 180
treeSmall -5,18 360
treeBig 22,11 45
treeSmall 10,-23 240
treeBig -10,-16 300
treeSmall -17,14 120
treeBig 20,4 150
treeSmall 11,-22 180
treeBig -24,-11 200
treeSmall 14,17 150
treeBig -8,-12 300
treeSmall 7,-18 100
treeBig -5,16 330
treeSmall 16,-14 200
treeBig 18,-8 90
treeSmall -23,-9 45
treeBig 24,10 300
treeSmall -4,19 180
treeBig 12,-5 330
treeSmall -19,16 100
treeBig 14,20 150
treeSmall 9,12 180
treeBig -22,8 60
treeSmall 6,18 360
treeBig 25,-9 45
treeBig -10,12 240
treeSmall 19,-17 100
treeSmall -13,19 90
treeSmall 16,-12 120
treeBig 22,-6 45
treeSmall -18,15 200
treeBig 14,-10 300
treeBig 6,10 330
treeSmall 17,18 90
treeBig -20,4 180
treeBig 19,-16 300
treeSmall -15,9 270
treeBig 12,22 360

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 MiB

After

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

View File

@@ -0,0 +1,79 @@
package pp.mdga;
import java.util.ResourceBundle;
/**
* Provides access to the resource bundle of the game.
*
* @see #BUNDLE
*/
public class Resources {
/**
* Create Resources constants.
*/
public static final int MAX_PLAYERS = 4;
public static final int MAX_PIECES = 4;
public static final int MAX_EYES = 6;
/**
* The resource bundle for the MDGA game.
*/
public static final ResourceBundle BUNDLE = ResourceBundle.getBundle("mdga"); //NON-NLS
/**
* Gets a string for the given key from the resource bundle in {@linkplain #BUNDLE}.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if {@code key} is {@code null}
* @throws java.util.MissingResourceException if no object for the given key can be found
* @throws ClassCastException if the object found for the given key is not a string
*/
public static String stringLookup(String key) {
return BUNDLE.getString(key);
}
/**
* Gets a int for the given key from the resource bundle in {@linkplain #BUNDLE}.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if {@code key} is {@code null}
* @throws java.util.MissingResourceException if no object for the given key can be found
* @throws ClassCastException if the object found for the given key is not a string
*/
public static int intLookup(String key) {
return Integer.parseInt(BUNDLE.getString(key));
}
/**
* Gets a boolean for the given key from the resource bundle in {@linkplain #BUNDLE}.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if {@code key} is {@code null}
* @throws java.util.MissingResourceException if no object for the given key can be found
* @throws ClassCastException if the object found for the given key is not a string
*/
public static boolean boolLookup(String key) {
return Boolean.parseBoolean(BUNDLE.getString(key));
}
/**
* Gets a double for the given key from the resource bundle in {@linkplain #BUNDLE}.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if {@code key} is {@code null}
* @throws java.util.MissingResourceException if no object for the given key can be found
* @throws ClassCastException if the object found for the given key is not a string
*/
public static double doubleLookup(String key) {
return Double.parseDouble(BUNDLE.getString(key));
}
/**
* Private constructor to prevent instantiation.
*/
private Resources() { /* do not instantiate */ }
}

View File

@@ -12,21 +12,38 @@ public class CeremonyState extends ClientState {
private final PodiumState podiumState = new PodiumState(this, logic);
private final StatisticsState statisticsState = new StatisticsState(this, logic);
/**
* Creates a new CeremonyState
*
* @param parent the parent state
* @param logic the game logic
*/
public CeremonyState(ClientState parent, ClientGameLogic logic) {
super(parent, logic);
}
/**
* Enters the new state machine
*/
@Override
public void enter() {
setState(podiumState);
logic.addNotification(createCeremonyNotification());
}
/**
* exits this state
*/
@Override
public void exit() {
currentState.exit();
}
/**
* This method is used to set a new SubState
*
* @param state the state to be set
*/
public void setState(CeremonyStates state){
if(this.currentState != null){
this.currentState.exit();
@@ -35,14 +52,29 @@ public void setState(CeremonyStates state){
currentState = state;
}
/**
* This method get the PodiumState
*
* @return the PodiumState
*/
public PodiumState getPodiumState(){
return podiumState;
}
/**
* This method get the StatisticsState
*
* @return the StatisticsState
*/
public StatisticsState getStatisticsState(){
return statisticsState;
}
/**
* This method is used to get the current State
*
* @return the current State
*/
public CeremonyStates getState(){
return currentState;
}

View File

@@ -1,5 +1,6 @@
package pp.mdga.client;
import pp.mdga.Resources;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Color;
import pp.mdga.game.Game;
@@ -13,6 +14,10 @@
import java.util.Map;
import java.util.UUID;
/**
* The ClientGameLogic class is the main class for the client side of the game.
* It is responsible for handling the game logic on the client side.
*/
public class ClientGameLogic implements ServerInterpreter {
static final System.Logger LOGGER = System.getLogger(ClientGameLogic.class.getName());
@@ -21,6 +26,8 @@ public class ClientGameLogic implements ServerInterpreter {
private ClientState state;
private final ArrayList<Notification> notifications = new ArrayList<>();
private boolean isHost;
private int ownPlayerID;
private String ownPlayerName;
private final DialogsState dialogsState = new DialogsState(null, this);
private final GameState gameState = new GameState(null, this);
@@ -28,6 +35,11 @@ public class ClientGameLogic implements ServerInterpreter {
private final InterruptState interruptState = new InterruptState(null, this);
private final SettingsState settingsState = new SettingsState(null, this);
/**
* Creates a new ClientGameLogic
*
* @param clientSender the client sender
*/
public ClientGameLogic(ClientSender clientSender) {
this.game = new Game();
this.clientSender = clientSender;
@@ -35,11 +47,21 @@ public ClientGameLogic(ClientSender clientSender) {
state = dialogsState;
}
/**
* This method is used to send a message to the server
*
* @param msg the message to be sent
*/
public void send(ClientMessage msg){
LOGGER.log(System.Logger.Level.INFO, "send {0}", msg);
clientSender.send(msg);
}
/**
* This method is used to get a piece by its id
* @param pieceId the UUID of the piece
* @return the piece
*/
private Piece getPiece(UUID pieceId){
for(Map.Entry<Color, PlayerData> entry : game.getBoard().getPlayerData().entrySet()){
for(Piece piece : entry.getValue().getPieces()){
@@ -51,216 +73,472 @@ private Piece getPiece(UUID pieceId){
return null;
}
/**
* This method returns the clientSender
*
* @return the clientSender
*/
public ClientSender getClientSender(){
return clientSender;
}
/**
* This method is used to get the ownPlayerId
*
* @return the ownPlayerId
*/
public int getOwnPlayerId() {
return ownPlayerID;
}
/**
* This method is used to get the ownPlayerName
*
* @return the ownPlayerName
*/
public String getOwnPlayerName() {
return ownPlayerName;
}
/**
* This method is used to set the ownPlayerName
*
* @param ownPlayerName the ownPlayerName to be set
*/
public void setOwnPlayerName(String ownPlayerName) {
this.ownPlayerName = ownPlayerName;
}
/**
* This method is used to set the ownPlayerId
*
* @param ownPlayerId the ownPlayerId to be set
*/
public void setOwnPlayerId(int ownPlayerId) {
this.ownPlayerID = ownPlayerId;
}
/**
* This method returns the game
*
* @return the game
*/
public Game getGame(){
return game;
}
/**
* This method returns the current State
*
* @return the current State
*/
public ClientState getState(){
return state;
}
/**
* This method returns if the client is a host
*
* @return if the client is a host
*/
public boolean isHost(){
return isHost;
}
/**
* This method returns the steps you can calculate steps
*
* @return the calculated moves as int
*/
public int getCalculatedMoves(){
return game.getDiceEyes() * game.getDiceModifier();
}
/**
* This method sets if the player is a host
*
* @param isHost the boolean value
*/
public void setHost(boolean isHost){
this.isHost = isHost;
}
/**
* This method calls the method received of the state
*
* @param msg the ActivePlayer message received
*/
@Override
public void received(ActivePlayerMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the AnyPiece message received
*/
@Override
public void received(AnyPieceMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the Briefing message received
*/
@Override
public void received(BriefingMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the Ceremony message received
*/
@Override
public void received(CeremonyMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the Dice message received
*/
@Override
public void received(DieMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the DiceAgain message received
*/
@Override
public void received(DiceAgainMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the DiceNow message received
*/
@Override
public void received(DiceNowMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the EndOfGame message received
*/
@Override
public void received(EndOfTurnMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the GameOver message received
*/
@Override
public void received(LobbyAcceptMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the LobbyDeny message received
*/
@Override
public void received(LobbyDenyMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the LobbyPlayerJoin message received
*/
@Override
public void received(LobbyPlayerJoinedMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the LobbyPlayerLeave message received
*/
@Override
public void received(LobbyPlayerLeaveMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the MoveMessage message received
*/
@Override
public void received(MoveMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the NoTurn message received
*/
@Override
public void received(NoTurnMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the PauseGame message received
*/
@Override
public void received(PauseGameMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the PlayCard message received
*/
@Override
public void received(PlayCardMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the PossibleCard message received
*/
@Override
public void received(PossibleCardMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the PossiblePiece message received
*/
@Override
public void received(PossiblePieceMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the RankingResponse message received
*/
@Override
public void received(RankingResponseMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the RankingRollAgain message received
*/
@Override
public void received(RankingRollAgainMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the ReconnectBriefing message received
*/
@Override
public void received(ReconnectBriefingMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the ResumeGame message received
*/
@Override
public void received(ResumeGameMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the ServerStartGame message received
*/
@Override
public void received(ServerStartGameMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the SelectTSK message received.
*/
@Override
public void received(ShutdownMessage msg) {state.received(msg);}
public void received(ShutdownMessage msg) {
addNotification(new InfoNotification(Resources.stringLookup("server.shutdown")));
addNotification(new StartDialogNotification());
setState(dialogsState);
}
/**
* Handles a IncorrectRequest message received from the server.
*
* @param msg the IncorrectRequest message received.
*/
@Override
public void received(StartBriefingMessage msg) {
state.received(msg);
}
@Override
public void received(PlayerDataMessage msg) {
public void received(IncorrectRequestMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the StartPiece message received
*/
@Override
public void received(StartPieceMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the UpdateReady message received
*/
@Override
public void received(UpdateReadyMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the UpdateTSK message received
*/
@Override
public void received(UpdateTSKMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the WaitPiece message received
*/
@Override
public void received(WaitPieceMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the Spectator message received.
*/
@Override
public void received(SpectatorMessage msg) {
state.received(msg);
}
/**
* This method calls the method received of the state
*
* @param msg the SelectPiece message received.
*/
@Override
public void received(SelectPieceMessage msg) {
state.received(msg);
}
/**
* This method calls the method selectPiece
*
* @param pieceId the pieceID
*/
public void selectPiece(UUID pieceId){
state.selectPiece(getPiece(pieceId));
}
/**
* This method call the method selectNExt of the state
*/
public void selectNext(){
state.selectNext();
}
/**
* This method calls the method selectCard of the state
*
* @param card the BonusCard to selected
*/
public void selectCard(BonusCard card){
state.selectCard(card);
}
/**
* This method call the method selectTsk of the state
*
* @param color the Color to be selected
*/
public void selectTsk(Color color){
state.selectTSK(color);
}
/**
* The method calls the method deselectTsk of the state
*
* @param color the color to be deselcted
*/
public void deselectTSK(Color color){
state.deselectTSK(color);
}
/**
* This method calls the selectDice method of the state
*/
public void selectDice(){
state.selectDice();
}
/**
* This method calls the selectName method of the state
*
* @param name the name to be set
*/
public void selectName(String name){
state.setName(name);
}
/**
* This method calls a method of the state base on the parameter value
*
* @param ready the value if this method should ready or unready
*/
public void selectReady(boolean ready){
if(ready){
state.selectReady();
@@ -269,62 +547,122 @@ public void selectReady(boolean ready){
}
}
/**
* This method calls the selectHost method of the state
*
* @param name the name of the player hosting
*/
public void selectHost(String name){
state.selectHost(name);
}
/**
* This method calls the selectLeave method of the state
*/
public void selectLeave(){
state.selectLeave();
}
/**
* This method calls the selectJoin method of the state
*
* @param ip the ip to cennect to
*/
public void selectJoin(String ip){
state.selectJoin(ip);
}
/**
* This method calls the selectAnimationEnd method of the state
*/
public void selectAnimationEnd(){
state.selectAnimationEnd();
}
/**
* This method calls the selectStart method of the state
*/
public void selectStart(){
state.selectStart();
}
/**
* This method calls the selectResume method of the state
*/
public void selectResume(){
state.selectResume();
}
/**
* This method is used to transition between states
*
* @param state the new state
*/
public void setState(ClientState state){
this.state.exit();
state.enter();
this.state = state;
}
/**
* This method is used to enter the interrupt state and save the previous state
*/
public void enterInterrupt(){
interruptState.enter();
interruptState.setPreviousState(state);
this.state = interruptState;
}
/**
* This method is used to get the GameState
*
* @return the GameState
*/
public GameState getGameState(){
return gameState;
}
/**
* This method is used to get the CeremonyState
*
* @return the CeremonyState
*/
public CeremonyState getCeremony(){
return ceremonyState;
}
/**
* This method is used to get the InterruptState
*
* @return the InterruptState
*/
public InterruptState getInterrupt(){
return interruptState;
}
/**
* This method is used to get the DialogsState
*
* @return the DialogsState
*/
public DialogsState getDialogs(){
return dialogsState;
}
/**
* This method is used to get the SettingsState
*
* @return the SettingsState
*/
public SettingsState getSettings(){
return settingsState;
}
/**
* This method is used to get the next notification
*
* @return the next notification
*/
public Notification getNotification(){
if(!notifications.isEmpty()){
return notifications.remove(0);
@@ -333,6 +671,11 @@ public Notification getNotification(){
}
}
/**
* This method is used to add a notification
*
* @param notification the notification to be added
*/
public void addNotification(Notification notification){
notifications.add(notification);
}

View File

@@ -37,159 +37,155 @@ public String toString(){
@Override
public void received(ActivePlayerMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(AnyPieceMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(BriefingMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(CeremonyMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(DieMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(DiceAgainMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(DiceNowMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(EndOfTurnMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(LobbyAcceptMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(LobbyDenyMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(LobbyPlayerJoinedMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(LobbyPlayerLeaveMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(MoveMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(NoTurnMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(PauseGameMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(PlayCardMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(PossibleCardMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(PossiblePieceMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(RankingResponseMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(RankingRollAgainMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(ReconnectBriefingMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(ResumeGameMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(ServerStartGameMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(ShutdownMessage msg) {LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);}
public void received(ShutdownMessage msg) {LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());}
@Override
public void received(StartPieceMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(UpdateReadyMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(UpdateTSKMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(SpectatorMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(SelectPieceMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(WaitPieceMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
@Override
public void received(StartBriefingMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
}
public void received(PlayerDataMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
public void received(IncorrectRequestMessage msg) {
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg.toString());
}
public void selectPiece(Piece piece) {
@@ -252,6 +248,11 @@ public void selectResume(){
LOGGER.log(Level.DEBUG, "Resume not allowed");
}
/**
* This method is used to create a CeremonyNotification
*
* @return the created CeremonyNotification
*/
protected CeremonyNotification createCeremonyNotification(){
CeremonyNotification notification = new CeremonyNotification();
for (var player : logic.getGame().getPlayers().entrySet()){

View File

@@ -11,30 +11,41 @@ public class DialogsState extends ClientState {
private DialogStates currentState;
private int ownPlayerID;
private String ownPlayerName;
private final LobbyState lobbyState = new LobbyState(this, logic);
private final NetworkDialogState networkDialogState = new NetworkDialogState(this, logic);
private final StartDialogState startDialogState = new StartDialogState(this, logic);
/**
* Creates a new DialogsState
*
* @param parent the parent state
* @param logic the game logic
*/
public DialogsState(ClientState parent, ClientGameLogic logic) {
super(parent, logic);
}
/**
* exits this state
*/
@Override
public void exit(){
currentState.exit();
}
/**
* Enters the new state machine
*/
@Override
public void enter(){
setState(startDialogState);
ownPlayerID = 0;
ownPlayerName = null;
}
/**
* This method is used to set a new SubState
*
* @param newState the state to be set
*/
public void setState(DialogStates newState){
if(currentState != null){
currentState.exit();
@@ -43,114 +54,188 @@ public void setState(DialogStates newState){
currentState = newState;
}
public int getOwnPlayerId() {
return ownPlayerID;
}
public String getOwnPlayerName() {
return ownPlayerName;
}
public void setOwnPlayerName(String ownPlayerName) {
this.ownPlayerName = ownPlayerName;
}
public void setOwnPlayerId(int ownPlayerId) {
this.ownPlayerID = ownPlayerId;
}
/**
* This method is used to get the lobbyState
*
* @return the lobbyState
*/
public LobbyState getLobby() {
return lobbyState;
}
/**
* This method is used to get the networkDialogState
*
* @return the networkDialogState
*/
public NetworkDialogState getNetworkDialog() {
return networkDialogState;
}
/**
* This method is used to get the startDialogState
*
* @return the startDialogState
*/
public StartDialogState getStartDialog() {
return startDialogState;
}
/**
* This method is used to call the selectLeave method of the current state
*/
@Override
public void selectLeave(){
currentState.selectLeave();
}
/**
* This method is used to call the selectName method of the current state
*
* @param name the name to be set
*/
@Override
public void setName(String name){
currentState.setName(name);
}
/**
* This method is used to call the selectTSK method of the current state
*
* @param color the color to be set
*/
@Override
public void selectTSK(Color color){
currentState.selectTSK(color);
}
/**
* This method is used to call the deselectTSK method of the current state
*
* @param color the color to be deselected
*/
@Override
public void deselectTSK(Color color){
currentState.deselectTSK(color);
}
/**
* This method is used to call the selectReady method of the current state
*/
@Override
public void selectReady(){
currentState.selectReady();
}
/**
* This method is used to call the selectUnready method of the current state
*/
@Override
public void selectUnready(){
currentState.selectUnready();
}
/**
* This method is used to call the selectStart method of the current state
*/
@Override
public void selectStart(){
currentState.selectStart();
}
/**
* This method is used to call the selectJoin method of the current state
*
* @param string the string to be set
*/
@Override
public void selectJoin(String string){
currentState.selectJoin(string);
}
/**
* This method is used to call the selectHost method of the current state
*
* @param name the name to be set
*/
@Override
public void selectHost(String name){
currentState.selectHost(name);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the LobbyPlayerJoin message received
*/
@Override
public void received(LobbyPlayerJoinedMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the LobbyPlayerLeave message received
*/
@Override
public void received(LobbyPlayerLeaveMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the UpdateTSKMessage message received
*/
@Override
public void received(UpdateTSKMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the UpdateReady message received
*/
@Override
public void received(UpdateReadyMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the ServerStartGame message received
*/
@Override
public void received(ServerStartGameMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the LobbyAccept message received
*/
@Override
public void received(PlayerDataMessage msg){
public void received(LobbyAcceptMessage msg){
currentState.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the LobbyDeny message received
*/
@Override
public void received(StartBriefingMessage msg){
public void received(LobbyDenyMessage msg){
currentState.received(msg);
}
/**
* This method is used to get the current state
*/
public DialogStates getState() {
return currentState;
}

View File

@@ -3,8 +3,10 @@
import pp.mdga.client.gameState.*;
import pp.mdga.game.BonusCard;
import pp.mdga.game.Piece;
import pp.mdga.message.client.LeaveGameMessage;
import pp.mdga.message.server.*;
import pp.mdga.notification.InterruptNotification;
import pp.mdga.notification.StartDialogNotification;
public class GameState extends ClientState {
@@ -58,132 +60,271 @@ public void setState(GameStates newState){
state = newState;
}
/**
* This method is used to call the selectAnimationEnd method of the current state
*/
@Override
public void selectAnimationEnd(){
state.selectAnimationEnd();
}
/**
* This method is used to call the selectDice method of the current state
*/
@Override
public void selectDice(){
state.selectDice();
}
/**
* This method is used to call the selectPiece method of the current state
*
* @param piece the piece to be selected
*/
@Override
public void selectPiece(Piece piece){
state.selectPiece(piece);
}
/**
* This method is used to call the selectCard method of the current state
*
* @param card the card to be selected
*/
@Override
public void selectCard(BonusCard card){
state.selectCard(card);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(PauseGameMessage msg){
logic.enterInterrupt();
logic.addNotification(new InterruptNotification(logic.getGame().getPlayers().get(msg.getPlayerId()).getColor()));
}
@Override
public void selectLeave(){
logic.send(new LeaveGameMessage());
logic.addNotification(new StartDialogNotification());
logic.setState(logic.getDialogs());
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(DieMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(RankingRollAgainMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(RankingResponseMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(SelectPieceMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(WaitPieceMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(StartPieceMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(NoTurnMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(MoveMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(CeremonyMessage msg){
state.received(msg);
logic.addNotification(createCeremonyNotification());
logic.setState(logic.getCeremony());
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(EndOfTurnMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(SpectatorMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(DiceAgainMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(PossibleCardMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(PlayCardMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(DiceNowMessage msg){
state.received(msg);
}
/**
* This method is used to call the received method of the current state
*
* @param msg the message to be received
*/
@Override
public void received(ActivePlayerMessage msg){
state.received(msg);
}
/**
* This method returns the current state
*
* @return the current state
*/
public GameStates getState(){
return state;
}
/**
* This method returns the AnimationState
*
* @return the AnimationState
*/
public AnimationState getAnimation() {
return animationState;
}
/**
* This method returns the DetermineStartPlayerState
*
* @return the DetermineStartPlayerState
*/
public DetermineStartPlayerState getDetermineStartPlayer() {
return determineStartPlayerState;
}
/**
* This method returns the SpectatorState
*
* @return the SpectatorState
*/
public SpectatorState getSpectator() {
return spectatorState;
}
/**
* This method returns the TurnState
*
* @return the TurnState
*/
public TurnState getTurn() {
return turnState;
}
/**
* This method returns the WaitingState
*
* @return the WaitingState
*/
public WaitingState getWaiting() {
return waitingState;
}

View File

@@ -49,14 +49,23 @@ public SettingStates getState(){
return currentState;
}
/**
* Returns the main settings state
*/
public MainSettingsState getMainSettingsState(){
return mainSettingsState;
}
/**
* Returns the audio settings state
*/
public AudioSettingsState getAudioSettingsState(){
return audioSettingsState;
}
/**
* Returns the video settings state
*/
public VideoSettingsState getVideoSettingsState(){
return videoSettingsState;
}

View File

@@ -10,9 +10,7 @@
import pp.mdga.message.client.*;
import pp.mdga.message.server.LobbyPlayerJoinedMessage;
import pp.mdga.message.server.LobbyPlayerLeaveMessage;
import pp.mdga.message.server.PlayerDataMessage;
import pp.mdga.message.server.ServerStartGameMessage;
import pp.mdga.message.server.StartBriefingMessage;
import pp.mdga.message.server.UpdateReadyMessage;
import pp.mdga.message.server.UpdateTSKMessage;
import pp.mdga.notification.*;
@@ -30,7 +28,7 @@ public LobbyState(ClientState parent, ClientGameLogic logic) {
@Override
public void enter() {
logic.send(new JoinedLobbyMessage(parent.getOwnPlayerName()));
logic.send(new JoinedLobbyMessage(logic.getOwnPlayerName()));
}
@Override
@@ -66,55 +64,46 @@ public void selectUnready(){
@Override
public void selectStart(){
if(logic.isHost() && logic.getGame().allReady()){
if(logic.isHost() && logic.getGame().areAllReady()){
logic.send(new StartGameMessage(false));
} else if(logic.isHost() && !logic.getGame().allReady()) {
} else if(logic.isHost() && !logic.getGame().areAllReady()) {
logic.send(new StartGameMessage(true));
} else {
LOGGER.log(System.Logger.Level.ERROR, "You are not the host");
}
}
@Override
public void received(StartBriefingMessage msg){
logic.getGame().setBoard(msg.getBoard());
}
public void received(PlayerDataMessage msg){
logic.getGame().getBoard().addPlayerData(msg.getColor(), msg.getPlayerData());
}
@Override
public void received(ServerStartGameMessage msg){
logic.addNotification(new GameNotification(logic.getGame().getPlayerById(parent.getOwnPlayerId()).getColor()));
for (Map.Entry<Color, PlayerData> entry : logic.getGame().getBoard().getPlayerData().entrySet()) {
List<UUID> pieceList = new ArrayList<>();
for(Piece piece : entry.getValue().getPieces()){
System.out.println(piece.getUuid());
pieceList.add(piece.getUuid());
logic.getGame().setBoard(msg.getBoard());
logic.addNotification(new GameNotification(logic.getGame().getPlayerById(logic.getOwnPlayerId()).getColor()));
for (Map.Entry<Integer, Player> entry : logic.getGame().getPlayers().entrySet()) {
List<UUID> pieces = new ArrayList<>();
for (Piece piece : logic.getGame().getBoard().getPlayerData().get(entry.getValue().getColor()).getPieces()) {
pieces.add(piece.getUuid());
}
logic.addNotification(new PlayerInGameNotification(entry.getKey(), pieceList , logic.getGame().getPlayerByColor(entry.getKey()).getName()));
logic.addNotification(new PlayerInGameNotification(entry.getValue().getColor(), pieces, entry.getValue().getName()));
}
logic.setState(logic.getGameState());
}
@Override
public void received(LobbyPlayerJoinedMessage msg){
if(msg.getPlayer().getName().equals(parent.getOwnPlayerName())){
parent.setOwnPlayerId(msg.getId());
if(msg.getPlayer().getName().equals(logic.getOwnPlayerName())){
logic.setOwnPlayerId(msg.getId());
}
if (msg.isHost() && msg.getId() == parent.getOwnPlayerId()){
if (msg.isHost() && msg.getId() == logic.getOwnPlayerId()){
logic.setHost(true);
}
logic.addNotification(new TskSelectNotification(msg.getPlayer().getColor(), msg.getPlayer().getName(), msg.getPlayer().getName().equals(parent.getOwnPlayerName())));
logic.addNotification(new TskSelectNotification(msg.getPlayer().getColor(), msg.getPlayer().getName(), msg.getPlayer().getName().equals(logic.getOwnPlayerName())));
logic.getGame().getPlayers().put(msg.getId(), msg.getPlayer());
}
@Override
public void received(UpdateTSKMessage msg){
if(msg.isTaken()) {
logic.addNotification(new TskSelectNotification(msg.getColor(), logic.getGame().getPlayers().get(msg.getId()).getName(), parent.getOwnPlayerId()== msg.getId()));
logic.addNotification(new TskSelectNotification(msg.getColor(), logic.getGame().getPlayers().get(msg.getId()).getName(), logic.getOwnPlayerId()== msg.getId()));
} else {
logic.addNotification(new TskUnselectNotification(logic.getGame().getPlayers().get(msg.getId()).getColor()));
}

View File

@@ -1,34 +1,72 @@
package pp.mdga.client.dialogState;
import pp.mdga.Resources;
import pp.mdga.client.ClientGameLogic;
import pp.mdga.client.ClientState;
import pp.mdga.client.DialogsState;
import pp.mdga.message.server.LobbyAcceptMessage;
import pp.mdga.message.server.LobbyDenyMessage;
import pp.mdga.notification.InfoNotification;
import pp.mdga.notification.LobbyDialogNotification;
public class NetworkDialogState extends DialogStates {
private final DialogsState parent;
/**
* Constructor for the NetworkDialogState
* @param parent the parent state
* @param logic the logic
*/
public NetworkDialogState(ClientState parent, ClientGameLogic logic) {
super(parent, logic);
this.parent = (DialogsState) parent;
}
/**
* Enter the state
*/
@Override
public void enter() {
LOGGER.log(System.Logger.Level.INFO, "Entered {0}", this);
}
/**
* Exit the state
*/
@Override
public void exit() {
}
/**
* Select the leave option
*/
@Override
public void selectLeave() {
parent.setState(parent.getStartDialog());
}
public void selectJoin(String IP) {
/**
* This method is called when the server accepts the client into the lobby
*
* @param msg the LobbyAcceptMessage
*/
@Override
public void received(LobbyAcceptMessage msg) {
logic.getGame().setHost(msg.getHost());
logic.setHost(logic.getGame().isHost());
parent.setState(parent.getLobby());
logic.addNotification(new LobbyDialogNotification());
}
/**
* This method is called when the server denies the client into the lobby
*
* @param msg the LobbyDenyMessage
*/
@Override
public void received(LobbyDenyMessage msg) {
logic.addNotification(new InfoNotification(Resources.stringLookup("lobby.deny.join")));
parent.setState(parent.getStartDialog());
}
}

View File

@@ -8,41 +8,44 @@ public class StartDialogState extends DialogStates {
private final DialogsState parent;
/**
* Constructor for the StartDialogState
* @param parent the parent state
* @param logic the logic
*/
public StartDialogState(ClientState parent, ClientGameLogic logic) {
super(parent, logic);
this.parent = (DialogsState) parent;
}
/**
* Enter the state
*/
@Override
public void enter() {
}
/**
* Exit the state
*/
@Override
public void exit() {
}
@Override
public void selectJoin(String name) {
parent.setOwnPlayerName(name);
parent.setState(parent.getNetworkDialog());
logic.setHost(false);
}
@Override
public void selectHost(String name) {
parent.setOwnPlayerName(name);
parent.setState(parent.getLobby());
logic.setHost(true);
}
/**
* Set the name
*
* @param name the name
*/
@Override
public void setName(String name) {
logic.setOwnPlayerName(name);
parent.setState(parent.getNetworkDialog());
parent.setOwnPlayerName(name);
}
/**
* Select the leave option
*/
@Override
public void selectLeave() {
parent.exit();

View File

@@ -36,14 +36,13 @@ protected void handlePowerCard(PlayCardMessage msg){
logic.getGame().getBoard().getInfield()[logic.getGame().getBoard().getInfieldIndexOfPiece(enemyPiece)].setOccupant(ownPiece);
logic.getGame().getBoard().getInfield()[ownIndex].setOccupant(enemyPiece);
}
logic.getGame().getPlayerByColor(logic.getGame().getActiveColor()).removeHandCard(msg.getCard());
logic.getGame().getDiscardPile().add(msg.getCard());
logic.getGame().getDiscardPile().add(logic.getGame().getPlayerByColor(logic.getGame().getActiveColor()).removeHandCard(msg.getCard()));
}
protected void throwPiece(Piece piece){
logic.getGame().getBoard().getInfield()[logic.getGame().getBoard().getInfieldIndexOfPiece(piece)].clearOccupant();
logic.getGame().getBoard().getPlayerData().get(piece.getColor()).addWaitingPiece(piece);
logic.addNotification(new ThrowPieceNotification(piece.getUuid()));
// logic.addNotification(new ThrowPieceNotification(piece.getUuid()));
logic.getGame().getPlayerByColor(piece.getColor()).getPlayerStatistic().increasePiecesBeingThrown();
logic.getGame().getGameStatistics().increasePiecesBeingThrown();
piece.setState(PieceState.WAITING);

View File

@@ -34,7 +34,7 @@ public void selectDice(){
@Override
public void received(DieMessage msg){
logic.addNotification(new RollDiceNotification(logic.getGame().getPlayerById(logic.getDialogs().getOwnPlayerId()).getColor(), msg.getDiceEye(),true));
logic.addNotification(new RollDiceNotification(logic.getGame().getPlayerById(logic.getOwnPlayerId()).getColor(), msg.getDiceEye(),true));
parent.setState(parent.getWaitRanking());
}
}

View File

@@ -29,7 +29,7 @@ public Board() {
} else if (i == 4 || i == 14 || i == 24 || i == 34) {
infield[i] = new BonusNode();
} else {
infield[i] = new Node();
infield[i] = new Node(null);
}
}
}

View File

@@ -8,6 +8,6 @@
@Serializable
public class BonusNode extends Node {
BonusNode(){
super();
super(null);
}
}

View File

@@ -1,9 +1,12 @@
package pp.mdga.game;
import com.jme3.network.serializing.Serializable;
/**
* This enumeration will be used to show the four different TSK which can be picked from a player.
* In Addition, the NONE color will be used to show a none color.
*/
@Serializable
public enum Color {
/**
* Represents the air force color.

View File

@@ -1,7 +1,11 @@
package pp.mdga.game;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.stream.IntStream;
/**
* This class represents a simple die with the possibilities to shuffle and return the roll result.
@@ -43,6 +47,14 @@ public class Die {
*/
private int lastNumberOfDice;
/**
* Predefined rolls for testing.
*/
private Iterator<Integer> rolls;
/**
* If the results of the die should be locked.
*/
private final boolean lock;
/**
@@ -65,7 +77,7 @@ public Die(long seed) {
/**
* Constructor.
*
*
* @param roll as the roll which should be returned everytime the shuffle method will be called as an Integer.
*/
public Die(int roll) {
@@ -74,6 +86,17 @@ public Die(int roll) {
this.lock = true;
}
/**
* Constructor.
*
* @param rolls as a variable list of rolls which will be used by test cases as an Array of Integers.
*/
public Die(int... rolls) {
this.random = RandomGeneratorFactory.of("Random").create();
this.rolls = IntStream.of(rolls).iterator();
this.lock = false;
}
/**
* This method will be used to return a random number generated by the random attribute of Die class.
*
@@ -84,6 +107,11 @@ public int shuffle() {
return this.lastNumberOfDice;
}
if (this.rolls != null && this.rolls.hasNext()) {
this.lastNumberOfDice = this.rolls.next();
return this.lastNumberOfDice;
}
this.lastNumberOfDice = this.random.nextInt(MAXIMUM_EYES) + 1;
return this.lastNumberOfDice;

View File

@@ -43,14 +43,11 @@ public class Game {
private Die die;
// The host of this game
private int host;
private int host = -1;
// The color of the active player.
private Color activeColor;
// A flag indicating whether all players are ready.
private boolean allReady = false;
/**
* This constructor creates a new Game object.
*/
@@ -65,6 +62,7 @@ public Game() {
drawPile.add(BonusCard.SHIELD);
}
board = new Board();
die = new Die();
}
/**
@@ -96,6 +94,38 @@ public void updatePlayerActiveState(int id, boolean active) {
this.players.get(id).setActive(active);
}
/**
* This method will be used to check if the given color parameter is already taken.
* If yes it will return true, otherwise false.
*
* @param color as the color which should be checked if taken as a Color enumeration.
* @return true or false.
*/
public boolean isColorTaken(Color color) {
for (Map.Entry<Integer, Player> entry : this.players.entrySet()) {
if (entry.getValue().getColor() == color) {
return true;
}
}
return false;
}
/**
* This method will be used to return the first unused color if possible.
*
* @return color as a Color enumeration.
*/
public Color getFirstUnusedColor() {
for (Color color : Color.values()) {
if (!isColorTaken(color)) {
return color;
}
}
return null;
}
/**
* This method will be used to return the player which has the given id parameter.
*
@@ -122,6 +152,32 @@ public Player getPlayerByColor(Color color) {
return null;
}
/**
* This method will be used to return the id of the active player depending on the activeColor attribute of Game
* class.
*
* @return the id of the active player as an Integer.
*/
public int getActivePlayerId() {
return this.getPlayerIdByColor(this.activeColor);
}
/**
* This method will be used to return the id of the Player defined by the given color parameter.
*
* @param color as the color of the player as a Color enumeration.
* @return the id of the player as an Integer.
*/
public int getPlayerIdByColor(Color color) {
for (Map.Entry<Integer, Player> entry : this.players.entrySet()) {
if (entry.getValue().getColor() == color) {
return entry.getKey();
}
}
return -1;
}
/**
* This method will be used to return the number of active players of this game.
*
@@ -138,6 +194,22 @@ public int getNumberOfActivePlayers() {
return activePlayers;
}
/**
* This method will be used to check if all players are ready.
* If yes it will return true, otherwise false.
*
* @return true or false.
*/
public boolean areAllReady() {
for (Map.Entry<Integer, Player> entry : this.players.entrySet()) {
if (!entry.getValue().isReady()) {
return false;
}
}
return true;
}
/**
* This method will be used to return a piece based on the UUID.
*
@@ -154,6 +226,15 @@ public Piece getPieceThroughUUID(UUID pieceId) {
return null;
}
/**
* This method will be used to check if this client is the host for the game.
*
* @return true or false.
*/
public boolean isHost() {
return this.host != -1;
}
/**
* This method returns the dice modifier.
*
@@ -333,22 +414,4 @@ public void setDie(Die die) {
public void setHost(int host) {
this.host = host;
}
/**
* This method returns the all ready state.
*
* @return the already state
*/
public Boolean allReady() {
return allReady;
}
/**
* This method sets the all ready state.
*
* @param allReady the new all-ready state
*/
public void setAllReady(Boolean allReady) {
this.allReady = allReady;
}
}

View File

@@ -8,6 +8,6 @@
@Serializable
public class HomeNode extends Node {
public HomeNode() {
super();
super(null);
}
}

View File

@@ -9,8 +9,12 @@
public class Node {
protected Piece occupant;
public Node(){
public Node(Piece piece){
occupant = piece;
}
private Node(){
occupant = new Piece(Color.AIRFORCE, PieceState.WAITING);
}
/**
@@ -49,4 +53,14 @@ public void clearOccupant() {
public boolean isOccupied() {
return occupant != null;
}
/**
* This method will be used to check if the node is occupied by a piece of the given color.
*
* @param color as the color of the piece as a Color object.
* @return true or false.
*/
public boolean isOccupied(Color color) {
return this.occupant != null && this.occupant.getColor() == color;
}
}

View File

@@ -35,12 +35,15 @@ public class Piece {
* @param color the color of the piece
* @param state the state of the piece
*/
public Piece(Color color, PieceState state, int id) {
public Piece(Color color, PieceState state) {
this.color = color;
this.state = state;
shield = ShieldState.NONE;
}
/**
* Constructor.
*/
private Piece() {
color = Color.NONE;
state = PieceState.WAITING;

View File

@@ -5,6 +5,7 @@
/**
* Represents the state of a piece.
*/
@Serializable
public enum PieceState {
/**
* The piece is active.
@@ -22,20 +23,4 @@ public enum PieceState {
* The piece is finished.
*/
HOMEFINISHED;
PieceState(){
}
public static PieceState getPieceStateByIndex(int index){
if (index < 0 || index >= values().length) {
throw new IllegalArgumentException("");
}
return values()[index];
}
public PieceState next() {
return values()[(ordinal() + 1) % values().length];
}
}

View File

@@ -1,6 +1,7 @@
package pp.mdga.game;
import com.jme3.network.serializing.Serializable;
import pp.mdga.Resources;
import java.util.ArrayList;
@@ -17,12 +18,12 @@ public class Player {
/**
* The statistics of the player.
*/
private Statistic playerStatistic;
private Statistic playerStatistic = new Statistic();
/**
* The hand cards of the player.
*/
private ArrayList<BonusCard> handCards;
private ArrayList<BonusCard> handCards = new ArrayList<>();
/**
* The color of the player.
@@ -32,13 +33,21 @@ public class Player {
/**
* Indicates if the player is ready.
*/
private boolean isReady;
private boolean ready = false;
/**
* Indicates if the player is active.
*/
private boolean active = true;
/**
* Node and piece attributes
*/
private int startNodeIndex = -1;
private HomeNode[] homeNodes = new HomeNode[Resources.MAX_PIECES];
private Piece[] waitingArea = new Piece[Resources.MAX_PIECES];
private Piece[] pieces = new Piece[Resources.MAX_PIECES];
/**
* This constructor constructs a new Player object
*
@@ -46,8 +55,6 @@ public class Player {
*/
public Player(String name) {
this.name = name;
playerStatistic = new Statistic();
handCards = new ArrayList<>();
}
/**
@@ -58,39 +65,14 @@ public Player() {
}
/**
* This method returns the give name of the Player
*
* @return the name of the player as a String
* This method will be used to initialize all nodes and pieces of the Player class.
*/
public String getName() {
return name;
}
/**
* This method sets the name of the player
*
* @param name the new name of the player
*/
public void setName(String name) {
this.name = name;
}
/**
* This methode returns the statistics of the player
*
* @return the statistics of the player
*/
public Statistic getPlayerStatistic() {
return playerStatistic;
}
/**
* This method returns the current handCards of the player
*
* @return the handCards of the player
*/
public ArrayList<BonusCard> getHandCards() {
return handCards;
public void initialize() {
for (int index = 0; index < Resources.MAX_PIECES; index++) {
this.homeNodes[index] = new HomeNode();
this.pieces[index] = new Piece(this.color, PieceState.WAITING);
this.waitingArea[index] = this.pieces[index];
}
}
/**
@@ -116,6 +98,58 @@ public BonusCard removeHandCard(BonusCard card) {
return cardToRemove;
}
/**
* This method will be used to add the given piece parameter to the first free slot inside the waitingArea attribute
* of Player class.
*
* @param piece as the piece which should be added to the waitingArea attribute of Player class as a Piece object.
*/
public void addWaitingPiece(Piece piece) {
for (int i = 0; i < Resources.MAX_PIECES; i++) {
if (this.waitingArea[i] == null) {
this.waitingArea[i] = piece;
return;
}
}
}
/**
* This method will be used to check if the player is finished.
* ToDo: Currently return always false. Implement logic!
*
* @return true or false.
*/
public boolean isFinished() {
return false;
}
/**
* This method returns the give name of the Player
*
* @return the name of the player as a String
*/
public String getName() {
return name;
}
/**
* This methode returns the statistics of the player
*
* @return the statistics of the player
*/
public Statistic getPlayerStatistic() {
return playerStatistic;
}
/**
* This method returns the current handCards of the player
*
* @return the handCards of the player
*/
public ArrayList<BonusCard> getHandCards() {
return handCards;
}
/**
* This method returns the color of the player
*
@@ -125,22 +159,13 @@ public Color getColor() {
return color;
}
/**
* This method sets the color of the player
*
* @param color the new color of the player
*/
public void setColor(Color color) {
this.color = color;
}
/**
* This method returns if the player is ready
*
* @return true if the player is ready, false otherwise
*/
public boolean isReady() {
return isReady;
return ready;
}
/**
@@ -152,13 +177,67 @@ public boolean isActive() {
return this.active;
}
/**
* This method will be used to return startNodeIndex of Player class.
*
* @return startNodeIndex as an Integer.
*/
public int getStartNodeIndex() {
return this.startNodeIndex;
}
/**
* This method will be used to return homeNodes attribute of Player class.
*
* @return homeNodes as an Array of Node objects.
*/
public Node[] getHomeNodes() {
return this.homeNodes;
}
/**
* This method will be used to return waitingArea attribute of Player class.
*
* @return waitingArea as an Array of Piece objects.
*/
public Piece[] getWaitingArea() {
return this.waitingArea;
}
/**
* This method will be used to return pieces attribute of Player class.
*
* @return pieces as an Array of Piece objects.
*/
public Piece[] getPieces() {
return this.pieces;
}
/**
* This method sets the name of the player
*
* @param name the new name of the player
*/
public void setName(String name) {
this.name = name;
}
/**
* This method sets the color of the player
*
* @param color the new color of the player
*/
public void setColor(Color color) {
this.color = color;
}
/**
* This method sets the player to ready
*
* @param ready true if the player is ready, false otherwise
*/
public void setReady(boolean ready) {
isReady = ready;
this.ready = ready;
}
/**

View File

@@ -1,6 +1,7 @@
package pp.mdga.game;
import com.jme3.network.serializing.Serializable;
import pp.mdga.Resources;
/**
* This class is used to represent PlayerData related to the board
@@ -33,12 +34,12 @@ public class PlayerData {
* @param color the color of the player
*/
public PlayerData(Color color) {
homeNodes = new HomeNode[4];
pieces = new Piece[4];
waitingArea = new Piece[4];
for (int i = 0; i < 4; i++) {
homeNodes = new HomeNode[Resources.MAX_PIECES];
pieces = new Piece[Resources.MAX_PIECES];
waitingArea = new Piece[Resources.MAX_PIECES];
for (int i = 0; i < Resources.MAX_PIECES; i++) {
homeNodes[i] = new HomeNode();
pieces[i] = new Piece(color, PieceState.WAITING, i);
pieces[i] = new Piece(color, PieceState.WAITING);
waitingArea[i] = pieces[i];
}
}
@@ -47,9 +48,9 @@ public PlayerData(Color color) {
* Constructor.
*/
private PlayerData() {
homeNodes = new HomeNode[4];
waitingArea = new Piece[4];
pieces = new Piece[4];
homeNodes = new HomeNode[Resources.MAX_PIECES];
waitingArea = new Piece[Resources.MAX_PIECES];
pieces = new Piece[Resources.MAX_PIECES];
}
/**
@@ -113,7 +114,7 @@ public Piece[] getPieces() {
* @param piece the piece to be added to the waiting area
*/
public void addWaitingPiece(Piece piece) {
for (int i = 0; i < 4; i++) {
for (int i = 0; i < Resources.MAX_PIECES; i++) {
if (waitingArea[i] == null) {
waitingArea[i] = piece;
return;
@@ -127,7 +128,7 @@ public void addWaitingPiece(Piece piece) {
* @return the piece that was removed from the waiting area
*/
public Piece removePieceFromWaitingArea() {
for (int i = 0; i < 4; i++) {
for (int i = 0; i < Resources.MAX_PIECES; i++) {
if (waitingArea[i] != null) {
Piece piece = waitingArea[i];
waitingArea[i] = null;
@@ -148,26 +149,30 @@ public void setPieceInHome(int index, Piece piece) {
}
/**
* This method returns the homeNodes
* This method will be used to return if the given piece parameter is inside the homNodes attribute of PlayerData
* class.
* If yes it will return true, otherwise false.
*
* @return the homeNodes
* @return true or false.
*/
public boolean homeIncludes(Piece piece) {
for (int i = 0; i < 4; i++) {
if (homeNodes[i].getOccupant() == piece) {
for (Node node : this.homeNodes) {
if (node.getOccupant() == piece) {
return true;
}
}
return false;
}
/**
* This method returns the homeNodes
* This method will be used to return the index of the given piece parameter in the homeNodes attribute of
* PlayerData class.
*
* @return the homeNodes
* @return index as an Integer.
*/
public int getIndexInHome(Piece piece) {
for (int i = 0; i < 4; i++) {
for (int i = 0; i < Resources.MAX_PIECES; i++) {
if (homeNodes[i].getOccupant() == piece) {
return i;
}
@@ -176,9 +181,10 @@ public int getIndexInHome(Piece piece) {
}
/**
* This method returns the homeNodes
* This method will be usd to check if the waitingArea attribute of PlayerData class is empty.
* If yes it will return false, otherwise true.
*
* @return the homeNodes
* @return true or false.
*/
public boolean hasPieceInWaitingArea() {
for (Piece piece : waitingArea) {

View File

@@ -1,11 +1,8 @@
package pp.mdga.game;
import com.jme3.network.serializing.Serializable;
/**
* Represents the state of a piece's shield.
*/
@Serializable
public enum ShieldState {
/**
* The shield is not active.
@@ -19,19 +16,4 @@ public enum ShieldState {
* The shield is suppressed, when the piece is on a start node.
*/
SUPPRESSED;
ShieldState(){
}
public static ShieldState getShieldStateByIndex(int index){
if (index < 0 || index >= values().length) {
throw new IllegalArgumentException("");
}
return values()[index];
}
public ShieldState next() {
return values()[(ordinal() + 1) % values().length];
}
}

View File

@@ -18,10 +18,12 @@ public class StartNode extends Node {
* @param color the color of the node
*/
public StartNode(Color color) {
super(null);
this.color = color;
}
private StartNode() {
super(null);
color = Color.NONE;
}

View File

@@ -0,0 +1,58 @@
package pp.mdga.message.server;
import com.jme3.network.serializing.Serializable;
@Serializable
public class IncorrectRequestMessage extends ServerMessage {
/**
* Create IncorrectRequestMessage attributes.
*/
private final int id;
/**
* Constructor.
*
* @param id as the id of the error message as an Integer.
*/
public IncorrectRequestMessage(int id) {
this.id = id;
}
/**
* Constructor.
*/
public IncorrectRequestMessage() {
this.id = 0;
}
/**
* Accepts a visitor to process this message.
*
* @param interpreter the visitor to process this message
*/
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
/**
* Gets the bundle key of the informational text to be shown at the client.
* This key is used to retrieve the appropriate localized text for display.
*
* @return the bundle key of the informational text
*/
@Override
public String getInfoTextKey() {
return "";
}
/**
* This method will be used to return necessary class information in a more readable format.
*
* @return information as a String.
*/
@Override
public String toString() {
return "IncorrectRequestMessage with id: %d".formatted(this.id);
}
}

View File

@@ -7,13 +7,39 @@
*/
@Serializable
public class LobbyAcceptMessage extends ServerMessage {
/**
* Create LobbyAcceptMessage attributes.
*/
private final int host;
/**
* Constructs a new LobbyAccept instance.
*/
public LobbyAcceptMessage() {
super();
this.host = -1;
}
/**
* Constructor.
*
* @param host as the id of the host as an Integer.
*/
public LobbyAcceptMessage(int host) {
super();
this.host = host;
}
/**
* This method will be used return host attribute of LobbyAcceptMessage class.
*
* @return host as an Integer.
*/
public int getHost() {
return this.host;
}
/**
* Accepts a visitor to process this message.
*
@@ -31,7 +57,7 @@ public void accept(ServerInterpreter interpreter) {
*/
@Override
public String toString() {
return "";
return "Lobby Accept";
}
/**

View File

@@ -31,7 +31,7 @@ public void accept(ServerInterpreter interpreter) {
*/
@Override
public String toString() {
return "";
return "LobbyDeny";
}
/**

View File

@@ -1,40 +0,0 @@
package pp.mdga.message.server;
import com.jme3.network.serializing.Serializable;
import pp.mdga.game.Color;
import pp.mdga.game.PlayerData;
@Serializable
public class PlayerDataMessage extends ServerMessage{
private final PlayerData playerData;
private final Color color;
public PlayerDataMessage(PlayerData playerData, Color color){
super();
this.playerData = playerData;
this.color = color;
}
private PlayerDataMessage(){
this(null, null);
}
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
@Override
public String getInfoTextKey() {
return "";
}
public PlayerData getPlayerData(){
return playerData;
}
public Color getColor(){
return color;
}
}

View File

@@ -211,11 +211,14 @@ public interface ServerInterpreter {
/**
* Handles a SelectTSK message received from the server.
*
* @param shutdownMessage the SelectTSK message received.
* @param msg the SelectTSK message received.
*/
void received(ShutdownMessage shutdownMessage);
void received(ShutdownMessage msg);
void received(StartBriefingMessage msg);
void received(PlayerDataMessage msg);
/**
* Handles a IncorrectRequest message received from the server.
*
* @param msg the IncorrectRequest message received.
*/
void received(IncorrectRequestMessage msg);
}

View File

@@ -8,13 +8,38 @@
*/
@Serializable
public class ServerStartGameMessage extends ServerMessage {
/**
* Create ServerStartGameMessage attributes.
*/
private final Board board;
/**
* Constructs a new ServerStartGame instance.
*/
public ServerStartGameMessage() {
super();
this.board = new Board();
}
/**
* Constructor.
*
* @param board as the board of the game as a Board object.
*/
public ServerStartGameMessage(Board board) {
super();
this.board = board;
}
/**
* This method will return board attribute of ServerStartGameMessage class.
*
* @return board as a Board object.
*/
public Board getBoard() {
return this.board;
}
/**
* Accepts a visitor to process this message.
*

Some files were not shown because too many files have changed in this diff Show More