23 Commits

Author SHA1 Message Date
Luca Puderbach
bb9727d54a Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-19 23:09:44 +01:00
Luca Puderbach
7da8b3e545 Spieler Lobby 2024-11-19 23:09:39 +01:00
Johannes Schmelz
b6968df451 Merge branch 'main' into 'gui'
Main

See merge request progproj/gruppen-ht24/Gruppe-02!13
2024-11-19 20:30:56 +00:00
Johannes Schmelz
aa986fb948 added backgroud music file 2024-11-19 20:51:24 +01:00
Yvonne Schmidt
6e63de6e99 Merge remote-tracking branch 'origin/gui' into gui 2024-11-19 19:54:40 +01:00
Yvonne Schmidt
962ecd08fa SettingsMenu hat neues design 2024-11-19 19:54:22 +01:00
Luca Puderbach
580a26b3ea Grundlage Toolbar 2024-11-19 19:50:25 +01:00
Johannes Schmelz
0cda6b5fa0 added first sound files 2024-11-19 19:40:27 +01:00
Johannes Schmelz
cc8c3795b8 added game sound logic 2024-11-19 19:27:52 +01:00
Johannes Schmelz
3c21165efb adjusted config params 2024-11-19 19:09:37 +01:00
Luca Puderbach
818fdf4670 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-19 17:44:57 +01:00
Luca Puderbach
b7d679b492 neue map 2024-11-19 17:44:52 +01:00
Yvonne Schmidt
a42093df23 SettingsMenu nochmal angepasst 2024-11-19 17:34:22 +01:00
Johannes Schmelz
6157db51da added server label 2024-11-19 14:46:11 +01:00
Yvonne Schmidt
843052989b Merge remote-tracking branch 'origin/gui' into gui 2024-11-18 23:04:43 +01:00
Yvonne Schmidt
8e01fa3192 SettingsMenu angepasst 2024-11-18 23:04:09 +01:00
Johannes Schmelz
e2126a7ea7 implemented self host for server 2024-11-18 23:01:34 +01:00
Luca Puderbach
0b46d14650 LobbyServer Einfügen 2024-11-18 18:56:42 +01:00
Luca Puderbach
9e28deedf7 Grundlagen Lobby 2024-11-18 18:30:35 +01:00
Luca Puderbach
9c0172b413 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-18 17:27:51 +01:00
Luca Puderbach
2933d022aa Veränderung Erreichen der Testwelt 2024-11-18 17:27:46 +01:00
Yvonne Schmidt
bdefb7193e Merge remote-tracking branch 'origin/gui' into gui 2024-11-18 17:13:13 +01:00
Yvonne Schmidt
69b68a6975 toolbar style hinzugefügt 2024-11-18 17:08:58 +01:00
25 changed files with 692 additions and 138 deletions

View File

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

View File

@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MonopolyServer" type="Application" factoryName="Application"
nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="pp.monopoly.server.MonopolyServer"/>
<module name="Projekte.monopoly.server.main"/>
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.monopoly.server.*"/>
<option name="ENABLED" value="true"/>
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>

View File

@@ -7,22 +7,21 @@
package pp.battleship.client;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId;
import static pp.battleship.Resources.lookup;
import pp.battleship.client.gui.GameMusic;
import pp.battleship.client.gui.VolumeSlider;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;
import static pp.battleship.Resources.lookup;
import static pp.util.PreferencesUtils.getPreferences;
/**
@@ -39,7 +38,7 @@ class Menu extends Dialog {
private final VolumeSlider slider;
/**
* Constructs the Menu dialog for the Battleship application.
* Constructs the Menu dialog for the Battleship application.+
*
* @param app the BattleshipApp instance
*/

View File

@@ -20,6 +20,8 @@ def sliderBgColor = color(0.5, 0.75, 0.75, 1)
def gradientColor = color(0.5, 0.75, 0.85, 0.5)
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white
def greyBackground = color(0.8, 0.8, 0.8, 1) // Grey background color
def redBorderColor = color(1, 0, 0, 1) // Red border color
@@ -61,6 +63,22 @@ selector("container", "pp") {
background.setColor(bgColor)
}
selector("toolbar") {
// Set the grey background
background = new QuadBackgroundComponent(greyBackground)
// Add a red border using a TbtQuadBackgroundComponent
def redBorder = TbtQuadBackgroundComponent.create(
texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png",
generateMips: false),
1, 1, 1, 1, 1,
1f, false)
redBorder.color = redBorderColor
background = greyBackground
// Optional: Set padding inside the toolbar
insets = new Insets3f(10, 10, 10, 10)
}
selector("slider", "pp") {
background = gradient.clone()
background.setColor(bgColor)
@@ -190,6 +208,7 @@ selector("slider.down.button", "pp") {
selector("checkbox", "pp") {
color = buttonEnabledColor
fontSize = 20
}
selector("rollup", "pp") {
@@ -213,3 +232,13 @@ selector("tab.button", "pp") {
buttonCommands = stdButtonCommands
}
selector("settings-title", "pp") {
fontSize = 48 // Set font size
background = new QuadBackgroundComponent(color(0.4157f, 0.4235f, 0.4392f, 1.0f)) // Grey background
}
selector("menu-button", "pp") {
fontSize = 40 // Set font size
background = new QuadBackgroundComponent(color(0.4157f, 0.4235f, 0.4392f, 1.0f)) // Grey background
}

View File

@@ -7,6 +7,7 @@ description = 'Monopoly Client'
dependencies {
implementation project(":jme-common")
implementation project(":monopoly:model")
implementation project(":monopoly:server")
implementation libs.jme3.desktop

View File

@@ -0,0 +1,122 @@
package pp.monopoly.client;
import static pp.util.PreferencesUtils.getPreferences;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.prefs.Preferences;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
/**
* Handles the background music beeing played. Is able to start and stop the music. Set the Volume of the Audio.
*/
public class GameMusic extends AbstractAppState{
private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameMusic.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS
private static final String VOLUME_PREF = "volume"; //NON-NLS
private AudioNode music;
/**
* Checks if sound is enabled in the preferences.
*
* @return {@code true} if sound is enabled, {@code false} otherwise.
*/
public static boolean enabledInPreferences() {
return PREFERENCES.getBoolean(ENABLED_PREF, true);
}
/**
* Checks if sound is enabled in the preferences.
*
* @return float to which the volume is set
*/
public static float volumeInPreferences() {
return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
}
/**
* Initializes the sound effects for the game.
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
*
* @param stateManager The state manager
* @param app The application
*/
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
music = loadSound(app, "Sound/background.ogg");
setVolume(volumeInPreferences());
music.setLooping(true);
if (isEnabled() && music != null) {
music.play();
}
}
/**
* Loads a sound from the specified file.
*
* @param app The application
* @param name The name of the sound file.
* @return The loaded AudioNode.
*/
private AudioNode loadSound(Application app, String name) {
try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false);
sound.setPositional(false);
return sound;
}
catch (AssetLoadException | AssetNotFoundException ex) {
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
}
return null;
}
/**
* Sets the enabled state of this AppState.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
*
* @param enabled {@code true} to enable the AppState, {@code false} to disable it.
*/
@Override
public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return;
if (music != null) {
if (enabled) {
music.play();
} else {
music.stop();
}
}
super.setEnabled(enabled);
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
}
/**
* Toggles the game sound on or off.
*/
public void toggleSound() {
setEnabled(!isEnabled());
}
/**
* Sets the volume of music
* @param vol the volume to which the music should be set
*/
public void setVolume(float vol){
music.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol);
}
}

View File

@@ -31,9 +31,17 @@ public class GameSound extends AbstractAppState implements GameEventListener {
private static final Preferences PREFERENCES = getPreferences(GameSound.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS
private AudioNode splashSound;
private AudioNode shipDestroyedSound;
private AudioNode explosionSound;
private AudioNode passStartSound;
private AudioNode eventCardSound;
private AudioNode gulagSound;
private AudioNode diceRollSound;
private AudioNode moneyCollectSound;
private AudioNode moneyLostSound;
private AudioNode tradeAcceptedSound;
private AudioNode tradeRejectedSound;
private AudioNode winnerSound;
private AudioNode looserSound;
private AudioNode buttonSound;
/**
* Checks if sound is enabled in the preferences.
@@ -75,6 +83,17 @@ public class GameSound extends AbstractAppState implements GameEventListener {
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
passStartSound = loadSound(app, "Sound/Effects/passStart.ogg");
eventCardSound = loadSound(app, "Sound/Effects/eventCard.ogg");
gulagSound = loadSound(app, "Sound/Effects/gulag.ogg");
diceRollSound = loadSound(app, "Sound/Effects/diceRoll.ogg");
moneyCollectSound = loadSound(app, "Sound/Effects/moneyCollect.ogg");
moneyLostSound = loadSound(app, "Sound/Effects/moneyLost.ogg");
tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg");
tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg");
winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
looserSound = loadSound(app, "Sound/Effects/looser.ogg");
buttonSound = loadSound(app, "Sound/Effects/button.ogg");
}
/**
@@ -98,32 +117,97 @@ public class GameSound extends AbstractAppState implements GameEventListener {
}
/**
* Plays the splash sound effect.
* Plays the passStart sound effect.
*/
public void splash() {
if (isEnabled() && splashSound != null)
splashSound.playInstance();
public void passStart() {
if (isEnabled() && passStartSound != null)
passStartSound.playInstance();
}
/**
* Plays the explosion sound effect.
* Plays the eventCard sound effect.
*/
public void explosion() {
if (isEnabled() && explosionSound != null)
explosionSound.playInstance();
public void eventCard() {
if (isEnabled() && eventCardSound != null)
eventCardSound.playInstance();
}
/**
* Plays sound effect when a ship has been destroyed.
* Plays the gulag sound effect.
*/
public void shipDestroyed() {
if (isEnabled() && shipDestroyedSound != null)
shipDestroyedSound.playInstance();
public void gulag() {
if (isEnabled() && gulagSound != null)
gulagSound.playInstance();
}
/**
* Plays the diceRoll sound effect.
*/
public void diceRoll() {
if (isEnabled() && diceRollSound != null)
diceRollSound.playInstance();
}
/**
* Plays the moneyCollect sound effect.
*/
public void moneyCollect() {
if (isEnabled() && moneyCollectSound != null)
moneyCollectSound.playInstance();
}
/**
* Plays the moneyLost sound effect.
*/
public void moneyLost() {
if (isEnabled() && moneyLostSound != null)
moneyLostSound.playInstance();
}
/**
* Plays the tradeAccepted sound effect.
*/
public void tradeAccepted() {
if (isEnabled() && tradeAcceptedSound != null)
tradeAcceptedSound.playInstance();
}
/**
* Plays the tradeRejected sound effect.
*/
public void tradeRejected() {
if (isEnabled() && tradeRejectedSound != null)
tradeRejectedSound.playInstance();
}
/**
* Plays the winner sound effect.
*/
public void winner() {
if (isEnabled() && winnerSound != null)
winnerSound.playInstance();
}
/**
* Plays the looser sound effect.
*/
public void looser() {
if (isEnabled() && looserSound != null)
looserSound.playInstance();
}
/**
* Plays the button sound effect.
*/
public void button() {
if (isEnabled() && buttonSound != null)
buttonSound.playInstance();
}
@Override
public void receivedEvent(SoundEvent event) {
switch (event.sound()) {
case PASS_START -> passStart();
case EVENT_CARD -> eventCard();
case GULAG -> eventCard();
case DICE_ROLL -> eventCard();
case MONEY_COLLECTED -> eventCard();
case MONEY_LOST -> eventCard();
case TRADE_ACCEPTED -> eventCard();
case TRADE_REJECTED -> eventCard();
case WINNER -> eventCard();
case LOSER -> eventCard();
case BUTTON -> eventCard();
}
}
}

View File

@@ -9,8 +9,10 @@ import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.BaseStyles;
import pp.dialog.DialogBuilder;
@@ -23,6 +25,7 @@ import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.server.MonopolyServer;
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
private BitmapText topText;
@@ -37,6 +40,8 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
private TestWorld testWorld;
private boolean isSettingsMenuOpen = false;
private boolean inputBlocked = false;
private MonopolyServer monopolyServer;
/**
* Path to the styles script for GUI elements.
*/
@@ -206,4 +211,25 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
}
/**
* Startet den Server in einem neuen Thread.
*/
public void startServer() {
new Thread(() -> {
try {
monopolyServer = new MonopolyServer(); // Erstelle Serverinstanz
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public MonopolyServer getMonopolyServer() {
return monopolyServer;
}
public ServerConnection getServerConnection() {
return serverConnection;
}
}

View File

@@ -1,7 +1,6 @@
package pp.monopoly.client;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;

View File

@@ -1,7 +1,11 @@
package pp.monopoly.client.gui;
import javax.swing.JOptionPane;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.network.Client;
import com.jme3.network.Network;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
@@ -14,20 +18,16 @@ import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.StartMenu;
import pp.monopoly.server.MonopolyServer;
/**
* CreateGameMenu class represents the menu for creating a new game.
*/
public class CreateGameMenu {
private final MonopolyApp app;
private final Container menuContainer;
private Geometry background;
private TextField serverAddressField;
private TextField portField;
/**
* Konstruktor für das CreateGameMenu.
*
* @param app Die Hauptanwendung (MonopolyApp)
*/
public CreateGameMenu(MonopolyApp app) {
this.app = app;
@@ -48,11 +48,11 @@ public class CreateGameMenu {
inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
inputContainer.addChild(new Label("Server-Adresse:"));
TextField serverAddressField = inputContainer.addChild(new TextField("localhost"));
serverAddressField = inputContainer.addChild(new TextField("localhost"));
serverAddressField.setPreferredWidth(400); // Breite des Textfelds
inputContainer.addChild(new Label("Port:"));
TextField portField = inputContainer.addChild(new TextField("42069"));
portField = inputContainer.addChild(new TextField("42069"));
portField.setPreferredWidth(400); // Breite des Textfelds
// Button-Container
@@ -65,25 +65,35 @@ public class CreateGameMenu {
cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(source -> goBackToStartMenu());
// "Spiel hosten"-Button
Button hostButton = buttonContainer.addChild(new Button("Spiel hosten"));
// "Selber hosten"-Button
Button hostButton = buttonContainer.addChild(new Button("Selber hosten"));
hostButton.setPreferredSize(new Vector3f(120, 40, 0));
hostButton.addClickCommands(source -> {
closeCreateGameMenu(); // Schließt das Menü
app.startTestWorld(); // Starte die TestWorld im selben Fenster
});
hostButton.addClickCommands(source -> startServerAndJoin());
// "Beitreten"-Button
// "Beitreten"-Button (vorerst funktionslos)
Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
// Placeholder für die Beitrittslogik
joinButton.addClickCommands(source -> joinServer());
// Serverstatus-Label
Label serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet"));
serverStatusLabel.setFontSize(24);
// Zentrierung des Containers
menuContainer.setLocalTranslation(
(app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
1 // Höhere Z-Ebene für den Vordergrund
(app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
1 // Höhere Z-Ebene für den Vordergrund
);
app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenTestWorld") && isPressed) {
app.startTestWorld(); // Öffnet die TestWorld
}
}
}, "OpenTestWorld");
app.getGuiNode().attachChild(menuContainer);
}
@@ -107,15 +117,43 @@ public class CreateGameMenu {
* Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
*/
private void goBackToStartMenu() {
closeCreateGameMenu(); // Schließt das Menü
StartMenu.createStartMenu(app); // Zeige das Startmenü
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
StartMenu.createStartMenu(app);
}
/**
* Entfernt das CreateGameMenu und dessen Hintergrund.
* Startet den Server und tritt nach 2 Sekunden der Lobby bei.
*/
private void closeCreateGameMenu() {
app.getGuiNode().detachChild(menuContainer); // Entfernt den Menü-Container
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
private void startServerAndJoin() {
new Thread(() -> {
app.start();
MonopolyServer server = new MonopolyServer();
server.run();
// Warte 2 Sekunden
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Verbinde mit dem Server
app.enqueue(() -> joinServer());
}).start();
}
/**
* Tritt dem Server basierend auf den Eingaben bei.
*/
private void joinServer() {
String serverAddress = serverAddressField.getText();
int port = Integer.parseInt(portField.getText());
app.getServerConnection().connect(serverAddress, port);
// Öffnet die Lobby
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
new LobbyMenu(app);
}
}

View File

@@ -1,51 +0,0 @@
package pp.monopoly.client.gui;
import com.jme3.math.ColorRGBA;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
public class GameMenu extends Dialog {
private final MonopolyApp app;
/**
* Constructs the SettingsMenu dialog for the Monopoly application.
*
* @param app the MonopolyApp instance
*/
public GameMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Add a title label for Settings
Label settingsTitle = new Label("Einstellungen", new ElementId("settings-title"));
settingsTitle.setFontSize(48); // Set font size for the title
settingsTitle.setColor(ColorRGBA.White);
// Add any settings-related components here, such as volume control, toggles, etc.
// Add a back button to return to StartMenu
Button backButton = new Button("Zurück", new ElementId("menu-button"));
backButton.setColor(ColorRGBA.White);
backButton.setFontSize(24);
backButton.addClickCommands(source -> returnToStartMenu());
// Add components to this dialog
addChild(settingsTitle);
addChild(backButton);
// You can add more settings components here, like checkboxes or sliders.
}
/**
* Returns to the StartMenu when the back button is clicked.
*/
private void returnToStartMenu() {
app.getDialogManager().close(this); // Close the current settings dialog
//TODO return zum Ausgangsmenü
}
}

View File

@@ -0,0 +1,99 @@
package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp;
public class LobbyMenu {
private final MonopolyApp app;
private final Container menuContainer;
private Geometry background;
public LobbyMenu(MonopolyApp app) {
this.app = app;
// Entfernt das CreateGameMenu (inklusive Hintergrund)
app.getGuiNode().detachAllChildren();
// Hintergrundbild laden und hinzufügen
addBackgroundImage();
// Hauptcontainer für das Menü
menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers
// Titel
Label title = menuContainer.addChild(new Label("Lobby"));
title.setFontSize(48);
// Spielerstatus anzeigen
Container playerListContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
playerListContainer.addChild(new Label("Spieler in der Lobby:"));
Label playersLabel = playerListContainer.addChild(new Label("Noch keine Spieler verbunden.")); // Beispieltext
// Buttons
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
buttonContainer.setPreferredSize(new Vector3f(400, 50, 0));
// "Bereit"-Button
Button readyButton = buttonContainer.addChild(new Button("Bereit"));
readyButton.setPreferredSize(new Vector3f(120, 40, 0));
readyButton.addClickCommands(source -> toggleReady(playersLabel));
// "Zurück"-Button
Button backButton = buttonContainer.addChild(new Button("Zurück"));
backButton.setPreferredSize(new Vector3f(120, 40, 0));
backButton.addClickCommands(source -> goBackToCreateGame());
// Zentrierung des Containers
menuContainer.setLocalTranslation(
(app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
1 // Höhere Z-Ebene für den Vordergrund
);
app.getGuiNode().attachChild(menuContainer);
}
/**
* Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
*/
private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, -1); // Hintergrundebene
app.getGuiNode().attachChild(background);
}
/**
* Schaltet den "Bereit"-Status um.
*/
private void toggleReady(Label playersLabel) {
// Beispiel-Logik für das Umschalten des Status
playersLabel.setText("Spielerstatus aktualisiert."); // Beispieltext
}
/**
* Geht zurück zum CreateGameMenu.
*/
private void goBackToCreateGame() {
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
new CreateGameMenu(app);
}
}

View File

@@ -23,6 +23,7 @@ public class SettingsMenu extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container settingsContainer;
private final Container backgroundContainer;
public SettingsMenu(MonopolyApp app) {
super(app.getDialogManager());
@@ -32,10 +33,17 @@ public class SettingsMenu extends Dialog {
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für das Menü
settingsContainer = new Container();
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
// Titel
Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title")));
settingsTitle.setFontSize(48);
@@ -44,24 +52,35 @@ public class SettingsMenu extends Dialog {
Container effectSoundContainer = settingsContainer.addChild(new Container());
effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label")));
effectSoundContainer.addChild(new Slider());
effectSoundContainer.addChild(new Checkbox("Aktivieren")).setChecked(true);
effectSoundContainer.addChild(new Checkbox("Soundeffekte an")).setChecked(true);
effectSoundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Hintergrundmusik: Slider und Checkbox
Container backgroundMusicContainer = settingsContainer.addChild(new Container());
backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
backgroundMusicContainer.addChild(new Slider());
backgroundMusicContainer.addChild(new Checkbox("Aktivieren")).setChecked(true);
backgroundMusicContainer.addChild(new Checkbox("Musik an")).setChecked(true);
backgroundMusicContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> app.stop());
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
settingsContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
1
4
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2,
3
);
app.getGuiNode().attachChild(settingsContainer);
@@ -90,6 +109,7 @@ public class SettingsMenu extends Dialog {
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren
app.unblockInputs(); // Eingaben wieder aktivieren

View File

@@ -80,7 +80,7 @@ public class TestWorld {
// Setze das Material mit Textur
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
Texture texture = app.getAssetManager().loadTexture("Pictures/board.png");
Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
mat.setTexture("ColorMap", texture);
geom.setMaterial(mat);

View File

@@ -0,0 +1,168 @@
package pp.monopoly.client.gui;
import java.util.Random;
import com.jme3.font.BitmapText;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp;
/**
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
* Die Buttons bewegen den Würfel auf dem Spielfeld.
*/
public class Toolbar2 {
private final MonopolyApp app;
private final Container toolbarContainer;
private final Geometry cube; // Referenz auf den Würfel
private final BitmapText positionText; // Anzeige für die aktuelle Position
private final float boardLimit = 0.95f; // Grenzen des Bretts
private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
/**
* Konstruktor für die Toolbar.
*
* @param app Die Hauptanwendung (MonopolyApp)
* @param cube Der Würfel, der bewegt werden soll
*/
public Toolbar2(MonopolyApp app, Geometry cube) {
this.app = app;
this.cube = cube;
// Erstelle die Toolbar
toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
// Setze die Position am unteren Rand und die Breite
toolbarContainer.setLocalTranslation(
0, // Links bündig
100, // Höhe über dem unteren Rand
0 // Z-Ebene
);
toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
// Füge Buttons zur Toolbar hinzu
initializeButtons();
// Füge die Toolbar zur GUI hinzu
app.getGuiNode().attachChild(toolbarContainer);
// Erstelle die Position-Anzeige
positionText = createPositionDisplay();
updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
}
/**
* Initialisiert die Buttons in der Toolbar.
*/
private void initializeButtons() {
addButton("Vorwärts", 1); // Bewegung nach vorne
addButton("Rückwärts", -1); // Bewegung nach hinten
addDiceRollButton(); // Würfel-Button
}
/**
* Fügt einen Button mit einer Bewegung hinzu.
*
* @param label Der Text des Buttons
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts)
*/
private void addButton(String label, int step) {
Button button = new Button(label);
button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
button.addClickCommands(source -> moveCube(step));
toolbarContainer.addChild(button);
}
/**
* Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
*/
private void addDiceRollButton() {
Button diceButton = new Button("Würfeln");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
}
/**
* Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
*/
private void rollDice() {
int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
System.out.println("Gewürfelt: " + diceRoll);
moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
}
/**
* Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
*
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
*/
private void moveCube(int step) {
currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
Vector3f newPosition = calculatePosition(currentPosition);
cube.setLocalTranslation(newPosition);
updatePositionDisplay(); // Aktualisiere die Positionsanzeige
System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
}
/**
* Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
*
* @param position Aktuelle Position auf dem Spielfeld
* @return Die berechnete Position als Vector3f
*/
private Vector3f calculatePosition(int position) {
int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
int offset = position % positionsPerSide; // Position auf der aktuellen Seite
switch (side) {
case 0: // Unten (positive x-Achse)
return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
case 1: // Rechts (positive z-Achse)
return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
case 2: // Oben (negative x-Achse)
return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
case 3: // Links (negative z-Achse)
return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
default:
throw new IllegalArgumentException("Ungültige Position: " + position);
}
}
/**
* Erstellt die Anzeige für die aktuelle Position.
*
* @return Das BitmapText-Objekt für die Anzeige
*/
private BitmapText createPositionDisplay() {
BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
text.setSize(20); // Schriftgröße
text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
app.getGuiNode().attachChild(text);
return text;
}
/**
* Aktualisiert die Anzeige für die aktuelle Position.
*/
private void updatePositionDisplay() {
positionText.setText("Feld-ID: " + currentPosition);
}
/**
* Entfernt die Toolbar.
*/
public void remove() {
app.getGuiNode().detachChild(toolbarContainer);
app.getGuiNode().detachChild(positionText);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -7,13 +7,10 @@
package pp.monopoly;
import pp.util.config.Config;
import java.util.Map;
import java.util.TreeMap;
import static java.lang.Math.max;
import pp.util.config.Config;
/**
* Provides access to the configuration settings for the Monopoly game.
* <p>
@@ -31,19 +28,19 @@ public class MonopolyConfig extends Config {
* The default port number for the Monopoly server.
*/
@Property("port")
private int port = 1234;
private int port = 42069;
/**
* The width of the game map in terms of grid units.
*/
@Property("map.width")
private int mapWidth = 10;
private int mapWidth = 11;
/**
* The height of the game map in terms of grid units.
*/
@Property("map.height")
private int mapHeight = 10;
private int mapHeight = 11;
/**
* Creates an instance of {@code MonopolyConfig} with default settings.

View File

@@ -1,50 +1,38 @@
package pp.monopoly.message.client;
import pp.monopoly.game.server.PlayerColor;
/**
* Represents a message indicating the player is ready to play.
*/
public class PlayerReady extends ClientMessage{
public class PlayerReady extends ClientMessage {
private boolean isReady;
private String name;
private PlayerColor color;
private String figure;
/**
* Constructs a PlayerReady message.
*
* @param isReady true if the player is ready, false otherwise
* @param name the name of the player
* @param color the color of the player (can be null)
*/
public PlayerReady(boolean isReady) {
public PlayerReady(boolean isReady, String name, String figure) {
this.isReady = isReady;
this.name = name;
this.figure = figure;
}
/**
* Getter for the Name
* @return the Name
*/
public String getName() {
return name;
}
/**
* Getter for the Playercolor
* @return the Playercolor
*/
public PlayerColor getColor() {
return color;
public String getFigure() {
return figure;
}
/**
* Checks if the player is ready.
*
* @return true if ready, false otherwise
*/
public boolean isReady() {
return isReady;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from);

View File

@@ -65,7 +65,7 @@ public class MonopolyServer implements MessageListener<HostedConnection>, Connec
/**
* Creates the server.
*/
MonopolyServer() {
public MonopolyServer() {
config.readFromIfExists(CONFIG_FILE);
LOGGER.log(Level.INFO, "Configuration: {0}", config); //NON-NLS
logic = new ServerGameLogic(this, config);