diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java index e09c724..df498f5 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java @@ -1,35 +1,28 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client; -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; -import pp.monopoly.notification.GameEventListener; -import pp.monopoly.notification.SoundEvent; - 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.audio.AudioData; +import com.jme3.audio.AudioNode; + +import pp.monopoly.notification.GameEventListener; +import pp.monopoly.notification.SoundEvent; import static pp.util.PreferencesUtils.getPreferences; /** - * An application state that plays sounds. + * An application state that plays sounds based on game events. */ public class GameSound extends AbstractAppState implements GameEventListener { private static final Logger LOGGER = System.getLogger(GameSound.class.getName()); private static final Preferences PREFERENCES = getPreferences(GameSound.class); - private static final String ENABLED_PREF = "enabled"; //NON-NLS + private static final String ENABLED_PREF = "enabled"; + + private Application app; // Feld zum Speichern der Application-Instanz /** * Checks if sound is enabled in the preferences. @@ -49,7 +42,6 @@ public class GameSound extends AbstractAppState implements GameEventListener { /** * 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. */ @@ -57,46 +49,52 @@ public class GameSound extends AbstractAppState implements GameEventListener { public void setEnabled(boolean enabled) { if (isEnabled() == enabled) return; super.setEnabled(enabled); - LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS + LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); PREFERENCES.putBoolean(ENABLED_PREF, enabled); } /** - * Initializes the sound effects for the game. - * Overrides {@link AbstractAppState#initialize(AppStateManager, Application)} + * Initializes the sound effects for the game and stores the application reference. * * @param stateManager The state manager - * @param app The application + * @param app The application instance */ @Override public void initialize(AppStateManager stateManager, Application app) { super.initialize(stateManager, app); + this.app = app; // Speichert die Application-Instanz } /** * 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) { + private AudioNode loadSound(String name) { try { - final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer); + AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer); sound.setLooping(false); sound.setPositional(false); return sound; - } - catch (AssetLoadException | AssetNotFoundException ex) { + } catch (Exception ex) { LOGGER.log(Level.ERROR, ex.getMessage(), ex); } return null; } + /** + * Handles sound-related game events to play specific sounds. + * + * @param event The sound event received. + */ @Override public void receivedEvent(SoundEvent event) { - switch (event.sound()) { - + if (isEnabled()) { + AudioNode sound = loadSound(event.getSoundFileName()); + if (sound != null) { + sound.play(); + } } } -} +}//heloo diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java index 34a281f..a9a22e5 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java @@ -7,17 +7,9 @@ package pp.monopoly.client; -import com.simsilica.lemur.Button; -import com.simsilica.lemur.Checkbox; -import com.simsilica.lemur.Label; -import com.simsilica.lemur.style.ElementId; -import pp.dialog.Dialog; -import pp.dialog.StateCheckboxModel; -import pp.dialog.TextInputDialog; - import java.util.prefs.Preferences; -import static pp.monopoly.Resources.lookup; +import pp.dialog.Dialog; import static pp.util.PreferencesUtils.getPreferences; /** diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java index be35056..3525708 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java @@ -1,428 +1,139 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client; -import com.jme3.app.DebugKeysAppState; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import com.jme3.app.SimpleApplication; -import com.jme3.app.StatsAppState; import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; -import com.jme3.input.MouseInput; import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.KeyTrigger; -import com.jme3.input.controls.MouseButtonTrigger; import com.jme3.system.AppSettings; import com.simsilica.lemur.GuiGlobals; import com.simsilica.lemur.style.BaseStyles; -import pp.monopoly.game.client.MonopolyClient; -import pp.monopoly.game.client.ClientGameLogic; -import pp.monopoly.game.client.ServerConnection; -import pp.monopoly.notification.ClientStateEvent; -import pp.monopoly.notification.GameEventListener; -import pp.monopoly.notification.InfoTextEvent; + import pp.dialog.DialogBuilder; import pp.dialog.DialogManager; import pp.graphics.Draw; +import pp.monopoly.game.client.ClientGameLogic; +import pp.monopoly.game.client.MonopolyClient; +import pp.monopoly.game.client.ServerConnection; +import pp.monopoly.notification.GameEventListener; +import pp.monopoly.notification.InfoTextEvent; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.LogManager; - -import static pp.monopoly.Resources.lookup; - -/** - * The main class for the Monopoly client application. - * It manages the initialization, input setup, GUI setup, and game states for the client. - */ public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener { - - /** - * Logger for logging messages within the application. - */ - private static final Logger LOGGER = System.getLogger(MonopolyApp.class.getName()); - - /** - * Path to the styles script for GUI elements. - */ - private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS - - /** - * Path to the font resource used in the GUI. - */ - private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS - - /** - * Path to the client configuration file, if one exists. - */ - private static final File CONFIG_FILE = new File("client.properties"); - - /** - * Input mapping name for mouse clicks. - */ - public static final String CLICK = "CLICK"; - - /** - * Input mapping name for the Escape key. - */ - private static final String ESC = "ESC"; - - /** - * Manager for handling dialogs within the application. - */ - private final DialogManager dialogManager = new DialogManager(this); - - /** - * The server connection instance, used for communicating with the game server. - */ - private final ServerConnection serverConnection; - - /** - * Instance of the {@link Draw} class for rendering graphics. - */ - private Draw draw; - - /** - * Text display at the top of the GUI for showing information to the user. - */ private BitmapText topText; - - /** - * Executor service for handling asynchronous tasks within the application. - */ - private ExecutorService executor; - - /** - * Handler for managing the client's game logic. - */ + private final ServerConnection serverConnection; private final ClientGameLogic logic; - - /** - * Configuration settings for the Monopoly client application. - */ private final MonopolyAppConfig config; - - /** - * Listener for handling actions triggered by the Escape key. - */ private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed); + private final DialogManager dialogManager = new DialogManager(this); + private final ExecutorService executor = Executors.newCachedThreadPool(); - static { - // Configure logging - LogManager manager = LogManager.getLogManager(); - try { - manager.readConfiguration(new FileInputStream("logging.properties")); - LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS - } - catch (IOException e) { - LOGGER.log(Level.INFO, e.getMessage()); - } - } + private final Draw draw; - /** - * Starts the Monopoly application. - * - * @param args Command-line arguments for launching the application. - */ public static void main(String[] args) { new MonopolyApp().start(); } - /** - * Constructs a new {@code MonopolyApp} instance. - * Initializes the configuration, server connection, and game logic listeners. - */ - private MonopolyApp() { + public MonopolyApp() { + this.draw = new Draw(assetManager); config = new MonopolyAppConfig(); - config.readFromIfExists(CONFIG_FILE); - serverConnection = makeServerConnection(); + serverConnection = new NetworkSupport(this); logic = new ClientGameLogic(serverConnection); logic.addListener(this); setShowSettings(config.getShowSettings()); setSettings(makeSettings()); } - /** - * Creates and configures application settings from the client configuration. - * - * @return A configured {@link AppSettings} object. - */ - private AppSettings makeSettings() { - final AppSettings settings = new AppSettings(true); - settings.setTitle(lookup("monopoly.name")); - settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight()); - settings.setFullscreen(config.fullScreen()); - settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer()); - settings.setGammaCorrection(config.useGammaCorrection()); - return settings; - } - - /** - * Factory method for creating a server connection based on the current - * client configuration. - * - * @return A {@link ServerConnection} instance, which could be a real or mock server. - */ - private ServerConnection makeServerConnection() { - return new NetworkSupport(this); - } - - /** - * Returns the dialog manager responsible for managing in-game dialogs. - * - * @return The {@link DialogManager} instance. - */ - public DialogManager getDialogManager() { - return dialogManager; - } - - /** - * Returns the game logic handler for the client. - * - * @return The {@link ClientGameLogic} instance. - */ - @Override - public ClientGameLogic getGameLogic() { - return logic; - } - - /** - * Returns the current configuration settings for the Monopoly client. - * - * @return The {@link MonopolyClientConfig} instance. - */ @Override public MonopolyAppConfig getConfig() { return config; } - /** - * Initializes the application. - * Sets up input mappings, GUI, game states, and connects to the server. - */ + @Override + public ClientGameLogic getGameLogic() { + return logic; + } + + private AppSettings makeSettings() { + final AppSettings settings = new AppSettings(true); + settings.setTitle("Monopoly Game"); + settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight()); + settings.setFullscreen(config.fullScreen()); + return settings; + } + @Override public void simpleInitApp() { - setPauseOnLostFocus(false); - draw = new Draw(assetManager); + stateManager.detach(stateManager.getState(com.jme3.app.StatsAppState.class)); //FPS-Anzeige + GuiGlobals.initialize(this); // Lemur initialisieren + BaseStyles.loadGlassStyle(); // Beispielstil für Lemur + GuiGlobals.getInstance().getStyles().setDefaultStyle("glass"); + setupInput(); - setupStates(); setupGui(); - createStartMenu(); - //serverConnection.connect(); + StartMenu.createStartMenu(this); } - private void createStartMenu() { - StartMenu.createStartMenu(); - } - - /** - * Sets up the graphical user interface (GUI) for the application. - */ private void setupGui() { - GuiGlobals.initialize(this); - BaseStyles.loadStyleResources(STYLES_SCRIPT); - GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS - final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS + BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); topText = new BitmapText(normalFont); - final int height = context.getSettings().getHeight(); - topText.setLocalTranslation(10f, height - 10f, 0f); - topText.setColor(config.getTopColor()); + topText.setLocalTranslation(10, settings.getHeight() - 10, 0); guiNode.attachChild(topText); } - /** - * Configures input mappings and sets up listeners for user interactions. - */ private void setupInput() { inputManager.deleteMapping(INPUT_MAPPING_EXIT); - inputManager.setCursorVisible(false); - inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE)); - inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); - inputManager.addListener(escapeListener, ESC); + inputManager.setCursorVisible(true); + inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE)); + inputManager.addListener(escapeListener, "ESC"); } - /** - * Initializes and attaches the necessary application states for the game. - */ - private void setupStates() { - if (config.getShowStatistics()) { - final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS - final StatsAppState stats = new StatsAppState(guiNode, normalFont); - stateManager.attach(stats); - } - flyCam.setEnabled(false); - stateManager.detach(stateManager.getState(StatsAppState.class)); - stateManager.detach(stateManager.getState(DebugKeysAppState.class)); - - attachGameSound(); - - //TODO add states - stateManager.attachAll(); - } - - /** - * Attaches the game sound state and sets its initial enabled state. - */ - private void attachGameSound() { - final GameSound gameSound = new GameSound(); - logic.addListener(gameSound); - gameSound.setEnabled(GameSound.enabledInPreferences()); - stateManager.attach(gameSound); - } - - /** - * Updates the application state every frame. - * This method is called once per frame during the game loop. - * - * @param tpf Time per frame in seconds. - */ - @Override - public void simpleUpdate(float tpf) { - super.simpleUpdate(tpf); - dialogManager.update(tpf); - logic.update(tpf); - } - - /** - * Handles the Escape key action to either close the top dialog or show the main menu. - * - * @param isPressed Indicates whether the Escape key is pressed. - */ private void escape(boolean isPressed) { if (!isPressed) return; - if (dialogManager.showsDialog()) - dialogManager.escape(); - else - new Menu(this).open(); + new StartMenu(this); + } + + void setInfoText(String text) { + topText.setText(text); + } + + @Override + public void receivedEvent(InfoTextEvent event) { + setInfoText(event.key()); + } + + @Override + public void stop(boolean waitFor) { + if (executor != null) executor.shutdownNow(); + serverConnection.disconnect(); + super.stop(waitFor); + } + + public DialogManager getDialogManager() { + return dialogManager; } - /** - * Returns the {@link Draw} instance used for rendering graphical elements in the game. - * - * @return The {@link Draw} instance. - */ public Draw getDraw() { return draw; } - /** - * Handles a request to close the application. - * If the request is initiated by pressing ESC, this parameter is true. - * - * @param esc If true, the request is due to the ESC key being pressed. - */ - @Override - public void requestClose(boolean esc) { /* do nothing */ } - - /** - * Closes the application, displaying a confirmation dialog if the client is connected to a server. - */ - public void closeApp() { - if (serverConnection.isConnected()) - confirmDialog(lookup("confirm.leaving"), this::close); - else - close(); - } - - /** - * Closes the application, disconnecting from the server and stopping the application. - */ - private void close() { - serverConnection.disconnect(); - stop(); - } - - /** - * Updates the informational text displayed in the GUI. - * - * @param text The information text to display. - */ - void setInfoText(String text) { - LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS - topText.setText(text); - } - - /** - * Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}. - * - * @param event The {@link InfoTextEvent} containing the key for the text to display. - */ - @Override - public void receivedEvent(InfoTextEvent event) { - LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS - setInfoText(lookup(event.key())); - } - - /** - * Handles client state events to update the game states accordingly. - * - * @param event The {@link ClientStateEvent} representing the state change. - */ - @Override - public void receivedEvent(ClientStateEvent event) { - //TODO - throw new UnsupportedOperationException("unimplemented method"); - } - - /** - * Returns the executor service used for handling multithreaded tasks. - * - * @return The {@link ExecutorService} instance. - */ public ExecutorService getExecutor() { - if (executor == null) - executor = Executors.newCachedThreadPool(); return executor; } - /** - * Stops the application, shutting down the executor service and halting execution. - * - * @param waitFor If true, waits for the application to stop before returning. - */ - @Override - public void stop(boolean waitFor) { - if (executor != null) executor.shutdownNow(); - super.stop(waitFor); + public void closeApp() { + stop(); } - /** - * Displays a confirmation dialog with a specified question and action for the "Yes" button. - * - * @param question The question to display in the dialog. - * @param yesAction The action to perform if "Yes" is selected. - */ - void confirmDialog(String question, Runnable yesAction) { + public void errorDialog(String errorMessage) { DialogBuilder.simple(dialogManager) - .setTitle(lookup("dialog.question")) - .setText(question) - .setOkButton(lookup("button.yes"), yesAction) - .setNoButton(lookup("button.no")) - .build() - .open(); - } - - /** - * Displays an error dialog with the specified error message. - * - * @param errorMessage The error message to display in the dialog. - */ - void errorDialog(String errorMessage) { - DialogBuilder.simple(dialogManager) - .setTitle(lookup("dialog.error")) - .setText(errorMessage) - .setOkButton(lookup("button.ok")) - .build() - .open(); + .setTitle("Fehler") + .setText(errorMessage) + .setOkButton("OK") + .build() + .open(); } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppConfig.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppConfig.java index 95070d2..e126f75 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppConfig.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppConfig.java @@ -8,6 +8,7 @@ package pp.monopoly.client; import com.jme3.math.ColorRGBA; + import pp.monopoly.game.client.MonopolyClientConfig; /** diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppState.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppState.java index 6342436..76b002e 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppState.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyAppState.java @@ -1,19 +1,13 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client; import com.jme3.app.Application; import com.jme3.app.state.AbstractAppState; import com.jme3.app.state.AppStateManager; + import pp.monopoly.game.client.ClientGameLogic; /** - * Abstract class representing a state in the Battleship game. + * Abstract class representing a state in the Monopoly game. * Extends the AbstractAppState from jMonkeyEngine to manage state behavior. */ public abstract class MonopolyAppState extends AbstractAppState { @@ -21,8 +15,6 @@ public abstract class MonopolyAppState extends AbstractAppState { /** * Creates a new MonopolyAppState that is initially disabled. - * - * @see #setEnabled(boolean) */ protected MonopolyAppState() { setEnabled(false); @@ -38,7 +30,9 @@ public abstract class MonopolyAppState extends AbstractAppState { public void initialize(AppStateManager stateManager, Application application) { super.initialize(stateManager, application); this.app = (MonopolyApp) application; - if (isEnabled()) enableState(); + if (isEnabled()) { + enableState(); + } } /** @@ -59,15 +53,6 @@ public abstract class MonopolyAppState extends AbstractAppState { return app.getGameLogic(); } - /** - * Checks if any dialog is currently displayed. - * - * @return true if any dialog is currently shown, false otherwise - */ - public boolean showsDialog() { - return app.getDialogManager().showsDialog(); - } - /** * Sets the enabled state of the MonopolyAppState. * If the new state is the same as the current state, the method returns. @@ -79,24 +64,21 @@ public abstract class MonopolyAppState extends AbstractAppState { if (isEnabled() == enabled) return; super.setEnabled(enabled); if (app != null) { - if (enabled) + if (enabled) { enableState(); - else + } else { disableState(); + } } } /** - * This method is called when the state is enabled. - * It is meant to be overridden by subclasses to perform - * specific actions when the state is enabled. + * Called when the state is enabled. Override to define specific behavior. */ protected abstract void enableState(); /** - * This method is called when the state is disabled. - * It is meant to be overridden by subclasses to perform - * specific actions when the state is disabled. + * Called when the state is disabled. Override to define specific behavior. */ protected abstract void disableState(); } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java index 6b6ea98..6671b7b 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java @@ -1,35 +1,27 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client; -import com.simsilica.lemur.Container; -import com.simsilica.lemur.Label; -import com.simsilica.lemur.TextField; -import com.simsilica.lemur.component.SpringGridLayout; -import pp.dialog.Dialog; -import pp.dialog.DialogBuilder; -import pp.dialog.SimpleDialog; - import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import static pp.monopoly.Resources.lookup; +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.Label; +import com.simsilica.lemur.TextField; + +import pp.dialog.Dialog; +import pp.dialog.DialogBuilder; +import pp.dialog.SimpleDialog; /** - * Represents a dialog for setting up a network connection in the Battleship game. + * Represents a dialog for setting up a network connection in the Monopoly game. * Allows users to specify the host and port for connecting to a game server. */ class NetworkDialog extends SimpleDialog { private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName()); - private static final String LOCALHOST = "localhost"; //NON-NLS - private static final String DEFAULT_PORT = "1234"; //NON-NLS + private static final String LOCALHOST = "localhost"; + private static final String DEFAULT_PORT = "1234"; private final NetworkSupport network; private final TextField host = new TextField(LOCALHOST); private final TextField port = new TextField(DEFAULT_PORT); @@ -46,56 +38,59 @@ class NetworkDialog extends SimpleDialog { NetworkDialog(NetworkSupport network) { super(network.getApp().getDialogManager()); this.network = network; - host.setSingleLine(true); - host.setPreferredWidth(400f); - port.setSingleLine(true); - - final MonopolyApp app = network.getApp(); - final Container input = new Container(new SpringGridLayout()); - input.addChild(new Label(lookup("host.name") + ": ")); - input.addChild(host, 1); - input.addChild(new Label(lookup("port.number") + ": ")); - input.addChild(port, 1); - - DialogBuilder.simple(app.getDialogManager()) - .setTitle(lookup("server.dialog")) - .setExtension(d -> d.addChild(input)) - .setOkButton(lookup("button.connect"), d -> connect()) - .setNoButton(lookup("button.cancel"), app::closeApp) - .setOkClose(false) - .setNoClose(false) - .build(this); + initializeDialog(); } /** - * Handles the action for the connect button in the connection dialog. - * Tries to parse the port number and initiate connection to the server. + * Initializes the dialog with input fields and connection buttons. + */ + private void initializeDialog() { + final MonopolyApp app = network.getApp(); + Container inputContainer = new Container(); + + // Titel und Eingabefelder für Host und Port + inputContainer.addChild(new Label("Server-Adresse")); + inputContainer.addChild(host); + + inputContainer.addChild(new Label("Port")); + inputContainer.addChild(port); + + Button connectButton = inputContainer.addChild(new Button("Verbinden")); + connectButton.addClickCommands(source -> connect()); + + Button cancelButton = inputContainer.addChild(new Button("Abbrechen")); + cancelButton.addClickCommands(source -> app.closeApp()); + + app.getGuiNode().attachChild(inputContainer); + } + + /** + * Initiates the connection attempt based on the entered host and port. */ private void connect() { - LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS + LOGGER.log(Level.INFO, "Connecting to host={0}, port={1}", host, port); try { hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText(); portNumber = Integer.parseInt(port.getText()); openProgressDialog(); connectionFuture = network.getApp().getExecutor().submit(this::initNetwork); - } - catch (NumberFormatException e) { - network.getApp().errorDialog(lookup("port.must.be.integer")); + } catch (NumberFormatException e) { + network.getApp().errorDialog("Port muss eine Zahl sein."); } } /** - * Creates a dialog indicating that the connection is in progress. + * Opens a progress dialog while connecting. */ private void openProgressDialog() { progressDialog = DialogBuilder.simple(network.getApp().getDialogManager()) - .setText(lookup("label.connecting")) + .setText("Verbinde zum Server...") .build(); progressDialog.open(); } /** - * Tries to initialize the network connection. + * Attempts to initialize the network connection. * * @throws RuntimeException If an error occurs when creating the client. */ @@ -103,40 +98,37 @@ class NetworkDialog extends SimpleDialog { try { network.initNetwork(hostname, portNumber); return null; - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException(e); } } /** - * This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically - * updating this dialog. T + * Updates the connection status and handles completion or failure. */ @Override public void update(float delta) { - if (connectionFuture != null && connectionFuture.isDone()) + if (connectionFuture != null && connectionFuture.isDone()) { try { connectionFuture.get(); - success(); - } - catch (ExecutionException e) { - failure(e.getCause()); - } - catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS + onSuccess(); + } catch (ExecutionException e) { + onFailure(e.getCause()); + } catch (InterruptedException e) { + LOGGER.log(Level.WARNING, "Connection interrupted.", e); Thread.currentThread().interrupt(); } + } } /** * Handles a successful connection to the game server. */ - private void success() { + private void onSuccess() { connectionFuture = null; progressDialog.close(); this.close(); - network.getApp().setInfoText(lookup("wait.for.an.opponent")); + network.getApp().setInfoText("Warte auf einen Gegner..."); } /** @@ -144,10 +136,10 @@ class NetworkDialog extends SimpleDialog { * * @param e The cause of the failure. */ - private void failure(Throwable e) { + private void onFailure(Throwable e) { connectionFuture = null; progressDialog.close(); - network.getApp().errorDialog(lookup("server.connection.failed")); + network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen."); network.getApp().setInfoText(e.getLocalizedMessage()); } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java index f6270bf..065bcf6 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java @@ -1,29 +1,21 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client; +import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; + import com.jme3.network.Client; import com.jme3.network.ClientStateListener; import com.jme3.network.Message; import com.jme3.network.MessageListener; import com.jme3.network.Network; + import pp.monopoly.game.client.ServerConnection; import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.server.ServerMessage; -import java.io.IOException; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; - -import static pp.monopoly.Resources.lookup; - /** - * Manages the network connection for the Battleship application. + * Manages the network connection for the Monopoly application. * Handles connecting to and disconnecting from the server, and sending messages. */ class NetworkSupport implements MessageListener, ClientStateListener, ServerConnection { @@ -32,18 +24,18 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se private Client client; /** - * Constructs a NetworkSupport instance for the given Battleship application. + * Constructs a NetworkSupport instance for the Monopoly application. * - * @param app The Battleship application instance. + * @param app The Monopoly application instance. */ public NetworkSupport(MonopolyApp app) { this.app = app; } /** - * Returns the Battleship application instance. + * Returns the Monopoly application instance. * - * @return Battleship application instance + * @return Monopoly application instance */ MonopolyApp getApp() { return app; @@ -65,8 +57,9 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se */ @Override public void connect() { - if (client == null) + if (client == null) { new NetworkDialog(this).open(); + } } /** @@ -77,7 +70,7 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se if (client == null) return; client.close(); client = null; - LOGGER.log(Level.INFO, "client closed"); //NON-NLS + LOGGER.log(Level.INFO, "Client connection closed."); } /** @@ -88,8 +81,9 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se * @throws IOException If an I/O error occurs when creating the client. */ void initNetwork(String host, int port) throws IOException { - if (client != null) - throw new IllegalStateException("trying to join a game again"); + if (client != null) { + throw new IllegalStateException("Already connected to the game server."); + } client = Network.connectToServer(host, port); client.start(); client.addMessageListener(this); @@ -104,9 +98,10 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se */ @Override public void messageReceived(Client client, Message message) { - LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS - if (message instanceof ServerMessage serverMessage) + LOGGER.log(Level.INFO, "Message received from server: {0}", message); + if (message instanceof ServerMessage serverMessage) { app.enqueue(() -> serverMessage.accept(app.getGameLogic())); + } } /** @@ -116,7 +111,7 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se */ @Override public void clientConnected(Client client) { - LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS + LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client); } /** @@ -127,13 +122,9 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se */ @Override public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) { - LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS - if (this.client != client) - throw new IllegalArgumentException("parameter value must be client"); - LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS + LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo); this.client = null; - disconnect(); - app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server"))); + app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren.")); } /** @@ -143,10 +134,11 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se */ @Override public void send(ClientMessage message) { - LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS - if (client == null) - app.errorDialog(lookup("lost.connection.to.server")); - else + LOGGER.log(Level.INFO, "Sending message to server: {0}", message); + if (client == null) { + app.errorDialog("Verbindung zum Server verloren."); + } else { client.send(message); + } } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java index d634bd2..c3893d3 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java @@ -1,30 +1,19 @@ package pp.monopoly.client; - import com.jme3.math.Vector3f; import com.simsilica.lemur.Button; -import com.simsilica.lemur.Checkbox; import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; -import com.simsilica.lemur.style.ElementId; + 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.monopoly.Resources.lookup; -import static pp.util.PreferencesUtils.getPreferences; +import pp.monopoly.client.gui.CreateGameMenu; +import pp.monopoly.client.gui.SettingsMenu; +/** + * Constructs the startup menu dialog for the Monopoly application. + */ public class StartMenu extends Dialog { - private static final Preferences PREFERENCES = getPreferences(StartMenu.class); - private static final String LAST_PATH = "last.file.path"; private final MonopolyApp app; - //private final Button playButton = new Button(lookup("Button.Play")); - //private final Button QuitButton = new Button(lookup("menu.quit")); - // private final Button GameMenu = new Button();/TODO Spielmenü Button funktionalität implementieren /** * Constructs the Startup Menu dialog for the Monopoly application. @@ -36,33 +25,55 @@ public class StartMenu extends Dialog { this.app = app; } - public static void createStartMenu() { + /** + * Creates and displays the Start Menu with buttons for starting the game, + * opening settings, and quitting the application. + */ + public static void createStartMenu(MonopolyApp app) { Container mainMenu = new Container(); - mainMenu.setLocalTranslation(new Vector3f(300, 300, 0)); // Positionierung + mainMenu.setLocalTranslation(new Vector3f(300, 300, 0)); // Positionierung des Menüs // Titel des Hauptmenüs mainMenu.addChild(new Label("Hauptmenü")); - // Schaltflächen hinzufügen + // Schaltfläche "Spielen" - Wechselt zum CreateGameMenu Button startButton = mainMenu.addChild(new Button("Spielen")); - startButton.addClickCommands(source -> startGame()); + startButton.addClickCommands(source -> startGame(app)); + // Schaltfläche "Einstellungen" - Öffnet das Einstellungsmenü Button settingsButton = mainMenu.addChild(new Button("Einstellungen")); - settingsButton.addClickCommands(source -> openSettings()); + settingsButton.addClickCommands(source -> openSettings(app)); + // Schaltfläche "Spiel beenden" - Beendet das Spiel Button quitButton = mainMenu.addChild(new Button("Spiel beenden")); quitButton.addClickCommands(source -> quitGame()); - attachChild(mainMenu); + // Hauptmenü dem Bildschirm hinzufügen + app.getGuiNode().attachChild(mainMenu); } - private void startGame() { - app.serverConnection.connect(); + /** + * Starts the game by transitioning to the CreateGameMenu. + */ + private static void startGame(MonopolyApp app) { + app.getGuiNode().detachAllChildren(); // Schließt das Startmenü + CreateGameMenu createGameMenu = new CreateGameMenu(app); + // Code zur Anzeige des CreateGameMenu, eventuell zusätzliche Initialisierung } - private void quitGame() { - + /** + * Opens the settings menu. + */ + private static void openSettings(MonopolyApp app) { + app.getGuiNode().detachAllChildren(); // Schließt das Startmenü + SettingsMenu settingsMenu = new SettingsMenu(app); + // Code zur Anzeige des SettingsMenu } + /** + * Quits the game application. + */ + private static void quitGame() { + System.exit(0); // Beendet die Anwendung + } } - diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/BoardSynchronizer.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/BoardSynchronizer.java index cfca711..f1819e4 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/BoardSynchronizer.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/BoardSynchronizer.java @@ -1,16 +1,10 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client.gui; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import pp.monopoly.model.Item; + import pp.monopoly.model.Board; +import pp.monopoly.model.Item; import pp.monopoly.model.Visitor; import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.ItemAddedEvent; @@ -21,30 +15,23 @@ import pp.view.ModelViewSynchronizer; * Abstract base class for synchronizing the visual representation of a {@link Board} with its model state. * This class handles the addition and removal of items from the map, ensuring that changes in the model * are accurately reflected in the view. - *

- * Subclasses are responsible for providing the specific implementation of how each item in the map - * is represented visually by implementing the {@link Visitor} interface. - *

*/ abstract class BoardSynchronizer extends ModelViewSynchronizer implements Visitor, GameEventListener { - // The map that this synchronizer is responsible for private final Board board; /** * Constructs a new BoardSynchronizer. - * Initializes the synchronizer with the provided map and the root node for attaching view representations. * - * @param map the map to be synchronized - * @param root the root node to which the view representations of the map items are attached + * @param board the game board to synchronize + * @param root the root node to which the view representations of the board items are attached */ - protected BoardSynchronizer(Board map, Node root) { + protected BoardSynchronizer(Board board, Node root) { super(root); - this.board = map; + this.board = board; } /** * Translates a model item into its corresponding visual representation. - * The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface. * * @param item the item from the model to be translated * @return the visual representation of the item as a {@link Spatial} @@ -55,35 +42,33 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer implements } /** - * Adds the existing items from the map to the view. - * This method should be called during initialization to ensure that all current items in the map - * are visually represented. + * Adds the existing items from the board to the view during initialization. */ protected void addExisting() { board.getItems().forEach(this::add); } /** - * Handles the event when an item is removed from the map. - * Removes the visual representation of the item from the view if it belongs to the synchronized map. + * Handles the event when an item is removed from the board. * - * @param event the event indicating that an item has been removed from the map + * @param event the event indicating that an item has been removed from the board */ @Override public void receivedEvent(ItemRemovedEvent event) { - if (board == event.map()) - delete(event.item()); + if (board == event.getBoard()) { + delete(event.getItem()); + } } /** - * Handles the event when an item is added to the map. - * Adds the visual representation of the new item to the view if it belongs to the synchronized map. + * Handles the event when an item is added to the board. * - * @param event the event indicating that an item has been added to the map + * @param event the event indicating that an item has been added to the board */ @Override public void receivedEvent(ItemAddedEvent event) { - if (board == event.map()) - add(event.item()); + if (board == event.getBoard()) { + add(event.getItem()); + } } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java new file mode 100644 index 0000000..94e942c --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java @@ -0,0 +1,77 @@ +package pp.monopoly.client.gui; + +import com.jme3.math.Vector3f; +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.Label; + +import pp.dialog.Dialog; +import pp.monopoly.client.MonopolyApp; +import pp.monopoly.client.StartMenu; + +/** + * Menu for creating a new game, where players can configure settings before starting. + */ +public class CreateGameMenu extends Dialog { + private final MonopolyApp app; + + /** + * Constructs the CreateGameMenu dialog for the Monopoly application. + * + * @param app the MonopolyApp instance + */ + public CreateGameMenu(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; + initializeMenu(); + } + + /** + * Sets up the Create Game Menu layout and buttons. + */ + private void initializeMenu() { + Container menuContainer = new Container(); + menuContainer.setLocalTranslation(new Vector3f(300, 300, 0)); // Positionierung des Menüs + + // Titel des Menüs + menuContainer.addChild(new Label("Neues Spiel erstellen")); + + // Beispiel-Button für die Spieleranzahl-Einstellung + Button playerCountButton = menuContainer.addChild(new Button("Spieleranzahl einstellen")); + playerCountButton.addClickCommands(source -> setPlayerCount()); + + // Start-Button zum Spielbeginn + Button startGameButton = menuContainer.addChild(new Button("Spiel starten")); + startGameButton.addClickCommands(source -> startGame()); + + // Zurück-Button zum Startmenü + Button backButton = menuContainer.addChild(new Button("Zurück")); + backButton.addClickCommands(source -> returnToStartMenu()); + + app.getGuiNode().attachChild(menuContainer); + } + + /** + * Placeholder for setting the player count. + */ + private void setPlayerCount() { + // Logik zum Festlegen der Spieleranzahl + System.out.println("Spieleranzahl einstellen wurde ausgewählt"); + } + + /** + * Placeholder for starting the game. + */ + private void startGame() { + // Logik für den Start des Spiels + System.out.println("Spiel starten wurde ausgewählt"); + } + + /** + * Returns to the StartMenu. + */ + private void returnToStartMenu() { + app.getGuiNode().detachAllChildren(); // Schließt das CreateGameMenu + StartMenu.createStartMenu(app); // Zeigt das Startmenü erneut an + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java index 0a20a66..638e402 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java @@ -1,55 +1,38 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client.gui; import com.jme3.material.Material; import com.jme3.material.RenderState.BlendMode; import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial.CullHint; import com.jme3.scene.shape.Quad; + import pp.monopoly.client.MonopolyApp; -import pp.monopoly.model.IntPoint; import pp.monopoly.model.Board; -import pp.util.FloatPoint; -import pp.util.Position; /** - * Represents the visual view of a {@link Board}, used to display the map structure such as the player's map, harbor, - * and opponent's map. This class handles the graphical representation of the map, including background setup, grid lines, - * and interaction between the model and the view. + * Represents the visual view of a {@link Board}, used to display the map structure and elements. + * This class handles the graphical representation of the board, including background setup and grid lines. */ class MapView { private static final float FIELD_SIZE = 40f; - private static final float GRID_LINE_WIDTH = 2f; private static final float BACKGROUND_DEPTH = -4f; - private static final float GRID_DEPTH = -1f; private static final ColorRGBA BACKGROUND_COLOR = new ColorRGBA(0, 0.05f, 0.05f, 0.5f); - private static final ColorRGBA GRID_COLOR = ColorRGBA.Green; - // Reference to the main application and the ship map being visualized private final MonopolyApp app; - private final Node mapNode = new Node("map"); // NON-NLS - private final Board map; + private final Node mapNode = new Node("map"); + private final Board board; private final MapViewSynchronizer synchronizer; /** * Constructs a new MapView for a given {@link Board} and {@link MonopolyApp}. - * Initializes the view by setting up the background and registering a synchronizer to listen to changes in the map. * - * @param map the ship map to visualize - * @param app the main application instance + * @param board the board to visualize + * @param app the main application instance */ - MapView(Board map, MonopolyApp app) { - this.map = map; + MapView(Board board, MonopolyApp app) { + this.board = board; this.app = app; this.synchronizer = new MapViewSynchronizer(this); setupBackground(); @@ -57,65 +40,26 @@ class MapView { } /** - * Unregisters the {@link MapViewSynchronizer} from the listener list of the ClientGameLogic, - * stopping the view from receiving updates when the underlying {@link Board} changes. - * After calling this method, this MapView instance should no longer be used. + * Unregisters the {@link MapViewSynchronizer} from listening to board changes. */ void unregister() { app.getGameLogic().removeListener(synchronizer); } - /** - * Gets the {@link Board} associated with this view. - * - * @return the ship map - */ - public Board getMap() { - return map; - } - - /** - * Gets the {@link MonopolyApp} instance associated with this view. - * - * @return the main application instance - */ - public MonopolyApp getApp() { - return app; - } - /** * Sets up the background of the map view using a quad geometry. - * The background is configured with a semi-transparent color and placed at a specific depth. */ private void setupBackground() { - final Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); // NON-NLS - mat.setColor("Color", BACKGROUND_COLOR); // NON-NLS + Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", BACKGROUND_COLOR); mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); - final Position corner = modelToView(map.getWidth(), map.getHeight()); - final Geometry background = new Geometry("MapBackground", new Quad(corner.getX(), corner.getY())); + Geometry background = new Geometry("MapBackground", new Quad(board.getWidth() * FIELD_SIZE, board.getHeight() * FIELD_SIZE)); background.setMaterial(mat); background.setLocalTranslation(0f, 0f, BACKGROUND_DEPTH); background.setCullHint(CullHint.Never); mapNode.attachChild(background); } - /** - * Adds grid lines to the map view to visually separate the fields within the map. - * The grid lines are drawn based on the dimensions of the ship map. - */ - public void addGrid() { - for (int x = 0; x <= map.getWidth(); x++) { - final Position f = modelToView(x, 0); - final Position t = modelToView(x, map.getHeight()); - mapNode.attachChild(gridLine(f, t)); - } - for (int y = 0; y <= map.getHeight(); y++) { - final Position f = modelToView(0, y); - final Position t = modelToView(map.getWidth(), y); - mapNode.attachChild(gridLine(f, t)); - } - } - /** * Gets the root node containing all visual elements in this map view. * @@ -125,67 +69,7 @@ class MapView { return mapNode; } - /** - * Gets the total width of the map in view coordinates. - * - * @return the width of the map in view coordinates - */ - public float getWidth() { - return FIELD_SIZE * map.getWidth(); - } - - /** - * Gets the total height of the map in view coordinates. - * - * @return the height of the map in view coordinates - */ - public float getHeight() { - return FIELD_SIZE * map.getHeight(); - } - - /** - * Converts coordinates from view coordinates to model coordinates. - * - * @param x the x-coordinate in view space - * @param y the y-coordinate in view space - * @return the corresponding model coordinates as an {@link IntPoint} - */ - public IntPoint viewToModel(float x, float y) { - return new IntPoint((int) Math.floor(x / FIELD_SIZE), (int) Math.floor(y / FIELD_SIZE)); - } - - /** - * Converts coordinates from model coordinates to view coordinates. - * - * @param x the x-coordinate in model space - * @param y the y-coordinate in model space - * @return the corresponding view coordinates as a {@link Position} - */ - public Position modelToView(float x, float y) { - return new FloatPoint(x * FIELD_SIZE, y * FIELD_SIZE); - } - - /** - * Converts the mouse position to model coordinates. - * This method takes into account the map's transformation in the 3D scene. - * - * @param pos the 2D vector representing the mouse position in the view - * @return the corresponding model coordinates as an {@link IntPoint} - */ - public IntPoint mouseToModel(Vector2f pos) { - final Vector3f world = new Vector3f(pos.getX(), pos.getY(), 0f); - final Vector3f view = mapNode.getWorldTransform().transformInverseVector(world, null); - return viewToModel(view.getX(), view.getY()); - } - - /** - * Creates a visual representation of a grid line between two positions. - * - * @param p1 the start position of the grid line - * @param p2 the end position of the grid line - * @return a {@link Geometry} representing the grid line - */ - private Geometry gridLine(Position p1, Position p2) { - return app.getDraw().makeFatLine(p1, p2, GRID_DEPTH, GRID_COLOR, GRID_LINE_WIDTH); + public Board getBoard() { + return board; } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java index d88dd05..c239394 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java @@ -1,63 +1,36 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.client.gui; -import com.jme3.math.ColorRGBA; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import pp.util.Position; - /** - * Synchronizes the visual representation of the ship map with the game model. - * It handles the rendering of ships and shots on the map view, updating the view - * whenever changes occur in the model. + * Synchronizes the visual representation of the board with the game model. + * Handles updates for items on the board. */ class MapViewSynchronizer extends BoardSynchronizer { - // Constants for rendering properties - private static final float SHIP_LINE_WIDTH = 6f; - private static final float SHOT_DEPTH = -2f; - private static final float SHIP_DEPTH = 0f; - private static final float INDENT = 4f; - - // Colors used for different visual elements - private static final ColorRGBA HIT_COLOR = ColorRGBA.Red; - private static final ColorRGBA MISS_COLOR = ColorRGBA.Blue; - private static final ColorRGBA SHIP_BORDER_COLOR = ColorRGBA.White; - private static final ColorRGBA PREVIEW_COLOR = ColorRGBA.Gray; - private static final ColorRGBA ERROR_COLOR = ColorRGBA.Red; - - // The MapView associated with this synchronizer private final MapView view; /** * Constructs a new MapViewSynchronizer for the given MapView. - * Initializes the synchronizer and adds existing elements from the model to the view. * * @param view the MapView to synchronize with the game model */ public MapViewSynchronizer(MapView view) { - super(view.getMap(), view.getNode()); + super(view.getBoard(), view.getNode()); this.view = view; addExisting(); } /** - * Creates a line geometry representing part of the ship's border. - * - * @param x1 the starting x-coordinate of the line - * @param y1 the starting y-coordinate of the line - * @param x2 the ending x-coordinate of the line - * @param y2 the ending y-coordinate of the line - * @param color the color of the line - * @return a Geometry representing the line + * Enables the state by performing initial setup, such as adding any items to the view. */ - private Geometry shipLine(float x1, float y1, float x2, float y2, ColorRGBA color) { - return view.getApp().getDraw().makeFatLine(x1, y1, x2, y2, SHIP_DEPTH, color, SHIP_LINE_WIDTH); + + protected void enableState() { + // Platz für zusätzliche Initialisierungen + } + + /** + * Disables the state by clearing the view. + */ + + protected void disableState() { + view.getNode().detachAllChildren(); // Entfernt alle visuellen Elemente vom Knoten } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java index 2db9af4..ffe4be1 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java @@ -1,13 +1,19 @@ package pp.monopoly.client.gui; - -import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; import com.simsilica.lemur.Button; +import com.simsilica.lemur.Checkbox; +import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; -import com.simsilica.lemur.style.ElementId; -import pp.dialog.Dialog; -import pp.monopoly.client.MonopolyApp; +import pp.dialog.Dialog; +import pp.monopoly.client.GameSound; +import pp.monopoly.client.MonopolyApp; +import pp.monopoly.client.StartMenu; + +/** + * Settings menu for the Monopoly application, where users can configure preferences. + */ public class SettingsMenu extends Dialog { private final MonopolyApp app; @@ -19,32 +25,46 @@ public class SettingsMenu extends Dialog { public SettingsMenu(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. + initializeMenu(); } /** - * Returns to the StartMenu when the back button is clicked. + * Sets up the layout and elements for the settings menu. + */ + private void initializeMenu() { + Container settingsContainer = new Container(); + settingsContainer.setLocalTranslation(new Vector3f(300, 300, 0)); // Positionierung des Menüs + + // Titel des Menüs + settingsContainer.addChild(new Label("Einstellungen")); + + // Beispiel-Einstellung: Sound aktivieren/deaktivieren + Checkbox soundCheckbox = settingsContainer.addChild(new Checkbox("Sound aktivieren")); + soundCheckbox.setChecked(GameSound.enabledInPreferences()); + soundCheckbox.addClickCommands(source -> toggleSound(soundCheckbox.isChecked())); + + // Zurück-Button zum Startmenü + Button backButton = settingsContainer.addChild(new Button("Zurück")); + backButton.addClickCommands(source -> returnToStartMenu()); + + app.getGuiNode().attachChild(settingsContainer); + } + + /** + * Toggles the sound setting and saves the preference. + * + * @param enabled true if sound should be enabled; false otherwise. + */ + private void toggleSound(boolean enabled) { + GameSound.enabledInPreferences(); // Speichert die Einstellung in den Preferences + System.out.println("Sound " + (enabled ? "aktiviert" : "deaktiviert")); + } + + /** + * Returns to the StartMenu. */ private void returnToStartMenu() { - app.getDialogManager().close(this); // Close the current settings dialog - //TODO return zum Ausgangsmenü + app.getGuiNode().detachAllChildren(); // Schließt das SettingsMenu + StartMenu.createStartMenu(app); // Zeigt das Startmenü erneut an } } diff --git a/Projekte/monopoly/client/src/main/resources/Board/Gameboard.png b/Projekte/monopoly/client/src/main/resources/Board/Gameboard.png new file mode 100644 index 0000000..ad8b7a8 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Board/Gameboard.png differ diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java index b230fdb..e46308f 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java @@ -7,15 +7,16 @@ package pp.monopoly.model; -import pp.monopoly.notification.GameEvent; -import pp.monopoly.notification.GameEventBroker; -import pp.monopoly.notification.ItemAddedEvent; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import pp.monopoly.notification.GameEvent; +import pp.monopoly.notification.GameEventBroker; +import pp.monopoly.notification.ItemAddedEvent; +import pp.monopoly.notification.ItemRemovedEvent; + /** * Represents a rectangular map that holds figures and registers houses, hotels * It also supports event notification for game state changes such as item addition or removal. @@ -65,7 +66,7 @@ public class Board { */ private void addItem(Item item) { items.add(item); - notifyListeners(new ItemAddedEvent(item, this)); + notifyListeners((GameEvent) new ItemAddedEvent(item, null)); } /** @@ -75,7 +76,7 @@ public class Board { */ public void remove(Item item) { items.remove(item); - notifyListeners(new ItemAddedEvent(item, this)); + notifyListeners((GameEvent) new ItemRemovedEvent(item, null)); // Falls es ein entsprechendes ItemRemovedEvent gibt } /** diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemAddedEvent.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemAddedEvent.java index f2e2749..00cb797 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemAddedEvent.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemAddedEvent.java @@ -1,29 +1,41 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.notification; -import pp.monopoly.model.Item; import pp.monopoly.model.Board; +import pp.monopoly.model.Item; /** - * Event when an item is added to a map. - * - * @param item the added item - * @param map the map that got the additional item + * Event that is triggered when an item is added to a board. */ -public record ItemAddedEvent(Item item, Board map) implements GameEvent { +public class ItemAddedEvent { + private final Item item; + private final Board board; + /** - * Notifies the game event listener of this event. + * Constructs a new ItemAddedEvent. * - * @param listener the game event listener + * @param item the item that was added + * @param board the board to which the item was added */ - @Override - public void notifyListener(GameEventListener listener) { - listener.receivedEvent(this); + public ItemAddedEvent(Item item, Board board) { + this.item = item; + this.board = board; + } + + /** + * Gets the item that was added. + * + * @return the added item + */ + public Item getItem() { + return item; + } + + /** + * Gets the board to which the item was added. + * + * @return the board + */ + public Board getBoard() { + return board; } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemRemovedEvent.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemRemovedEvent.java index 76a19dc..c7447cc 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemRemovedEvent.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/ItemRemovedEvent.java @@ -7,22 +7,30 @@ package pp.monopoly.notification; -import pp.monopoly.model.Item; import pp.monopoly.model.Board; +import pp.monopoly.model.Item; /** * Event when an item gets removed. * * @param item the destroyed item */ -public record ItemRemovedEvent(Item item, Board map) implements GameEvent { - /** - * Notifies the game event listener of this event. - * - * @param listener the game event listener - */ - @Override - public void notifyListener(GameEventListener listener) { - listener.receivedEvent(this); +public class ItemRemovedEvent { + private final Item item; + private final Board board; + + public ItemRemovedEvent(Item item, Board board) { + this.item = item; + this.board = board; + } + + public Item getItem() { + return item; + } + + public Board getBoard() { + return board; } } + + diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/Sound.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/Sound.java index 280ad4f..6bbe2cb 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/Sound.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/Sound.java @@ -4,5 +4,17 @@ package pp.monopoly.notification; * Enumeration representing different types of sounds used in the game. */ public enum Sound { + CLICK("click_sound.wav"), + WIN("win_sound.wav"), + LOSE("lose_sound.wav"); -} + private final String fileName; + + Sound(String fileName) { + this.fileName = fileName; + } + + public String getFileName() { + return fileName; + } +} \ No newline at end of file diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/SoundEvent.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/SoundEvent.java index 2eaaefe..b42ed7d 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/SoundEvent.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/notification/SoundEvent.java @@ -1,26 +1,25 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.notification; /** - * Event when an item is added to a map. + * Event when a sound needs to be played. * - * @param sound the sound to be played + * @param soundFileName the sound file to be played */ -public record SoundEvent(Sound sound) implements GameEvent { +public class SoundEvent implements GameEvent { + private final String soundFileName; + + public SoundEvent(Sound sound) { + this.soundFileName = sound.getFileName(); // Angenommen, Sound hat eine Methode getFileName() + } + + public String getSoundFileName() { + return soundFileName; + } - /** - * Notifies the game event listener of this event. - * - * @param listener the game event listener - */ @Override public void notifyListener(GameEventListener listener) { listener.receivedEvent(this); } } + +