mirror of
				https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
				synced 2025-10-31 05:31:50 +01:00 
			
		
		
		
	Merge branch 'main' into 'Testhandbuch'
# Conflicts: # Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy # Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java # Projekte/monopoly/model/src/test/java/pp/monopoly/client/ClientLogicTest.java # Projekte/monopoly/model/src/test/java/pp/monopoly/game/client/ClientGameLogicTest.java
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,6 +4,7 @@ build | ||||
|  | ||||
| # VSC | ||||
| bin | ||||
| .vscode | ||||
|  | ||||
| # IntelliJ | ||||
| *.iml | ||||
|   | ||||
| @@ -20,8 +20,6 @@ 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 | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,6 @@ 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; | ||||
| @@ -25,7 +24,6 @@ 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; | ||||
| @@ -40,8 +38,6 @@ 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. | ||||
|      */ | ||||
| @@ -98,10 +94,6 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga | ||||
|         StartMenu.createStartMenu(this); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     private void setupGui() { | ||||
|         BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); | ||||
|         topText = new BitmapText(normalFont); | ||||
| @@ -116,7 +108,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga | ||||
|         inputManager.addListener(escapeListener, "ESC"); | ||||
|     } | ||||
|  | ||||
|     void handleEscape(boolean isPressed) { | ||||
|     private void handleEscape(boolean isPressed) { | ||||
|         if (isPressed) { | ||||
|             if (settingsMenu != null && isSettingsMenuOpen) { | ||||
|                 // Schließe das SettingsMenu | ||||
| @@ -215,21 +207,4 @@ 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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| 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; | ||||
|   | ||||
| @@ -0,0 +1,59 @@ | ||||
| package pp.monopoly.client.gui; | ||||
|  | ||||
| import com.jme3.math.FastMath; | ||||
| import com.jme3.math.Vector3f; | ||||
| import com.jme3.renderer.Camera; | ||||
|  | ||||
| /** | ||||
|  * Steuert die Kamerabewegung in der Szene. | ||||
|  */ | ||||
| public class CameraController { | ||||
|     private final Camera camera; | ||||
|     private final Vector3f center; // Fokuspunkt der Kamera | ||||
|     private final float radius;    // Radius der Kreisbewegung | ||||
|     private final float height;    // Höhe der Kamera über dem Spielfeld | ||||
|     private final float speed;     // Geschwindigkeit der Kamerabewegung | ||||
|     private float angle;           // Aktueller Winkel in der Kreisbewegung | ||||
|  | ||||
|     /** | ||||
|      * Konstruktor für den CameraController. | ||||
|      * | ||||
|      * @param camera Die Kamera, die gesteuert werden soll | ||||
|      * @param center Der Mittelpunkt der Kreisbewegung (Fokuspunkt) | ||||
|      * @param radius Der Radius der Kreisbewegung | ||||
|      * @param height Die Höhe der Kamera über dem Fokuspunkt | ||||
|      * @param speed  Die Geschwindigkeit der Kamerabewegung | ||||
|      */ | ||||
|     public CameraController(Camera camera, Vector3f center, float radius, float height, float speed) { | ||||
|         this.camera = camera; | ||||
|         this.center = center; | ||||
|         this.radius = radius; | ||||
|         this.height = height; | ||||
|         this.speed = speed; | ||||
|         this.angle = 0; // Starte bei Winkel 0 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Aktualisiert die Kameraposition und -ausrichtung. | ||||
|      * | ||||
|      * @param tpf Zeit pro Frame | ||||
|      */ | ||||
|     public void update(float tpf) { | ||||
|         // Aktualisiere den Winkel basierend auf der Geschwindigkeit | ||||
|         angle += speed * tpf; | ||||
|         if (angle >= FastMath.TWO_PI) { | ||||
|             angle -= FastMath.TWO_PI; // Winkel zurücksetzen, um Überläufe zu vermeiden | ||||
|         } | ||||
|  | ||||
|         // Berechne die neue Position der Kamera | ||||
|         float x = center.x + radius * FastMath.cos(angle); | ||||
|         float z = center.z + radius * FastMath.sin(angle); | ||||
|         float y = center.y + height; | ||||
|  | ||||
|         // Setze die Kameraposition | ||||
|         camera.setLocation(new Vector3f(x, y, z)); | ||||
|  | ||||
|         // Lasse die Kamera auf den Fokuspunkt blicken | ||||
|         camera.lookAt(center, Vector3f.UNIT_Y); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,121 @@ | ||||
| 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.TextField; | ||||
| import com.simsilica.lemur.component.SpringGridLayout; | ||||
|  | ||||
| import pp.monopoly.client.MonopolyApp; | ||||
| import pp.monopoly.client.StartMenu; | ||||
|  | ||||
| /** | ||||
|  * CreateGameMenu class represents the menu for creating a new game. | ||||
|  */ | ||||
| public class CreateGameMenu { | ||||
|     private final MonopolyApp app; | ||||
|     private final Container menuContainer; | ||||
|     private Geometry background; | ||||
|  | ||||
|     /** | ||||
|      * Konstruktor für das CreateGameMenu. | ||||
|      * | ||||
|      * @param app Die Hauptanwendung (MonopolyApp) | ||||
|      */ | ||||
|     public CreateGameMenu(MonopolyApp app) { | ||||
|         this.app = app; | ||||
|  | ||||
|         // 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("Neues Spiel")); | ||||
|         title.setFontSize(48); | ||||
|  | ||||
|         // Eingabefelder-Container | ||||
|         Container inputContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X))); | ||||
|         inputContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Eingabefelder nicht ganz so breit | ||||
|         inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand | ||||
|  | ||||
|         inputContainer.addChild(new Label("Server-Adresse:")); | ||||
|         TextField 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.setPreferredWidth(400); // Breite des Textfelds | ||||
|  | ||||
|         // Button-Container | ||||
|         Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); | ||||
|         buttonContainer.setPreferredSize(new Vector3f(400, 50, 0)); | ||||
|         buttonContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand | ||||
|  | ||||
|         // "Abbrechen"-Button | ||||
|         Button cancelButton = buttonContainer.addChild(new Button("Abbrechen")); | ||||
|         cancelButton.setPreferredSize(new Vector3f(120, 40, 0)); | ||||
|         cancelButton.addClickCommands(source -> goBackToStartMenu()); | ||||
|  | ||||
|         // "Spiel hosten"-Button | ||||
|         Button hostButton = buttonContainer.addChild(new Button("Spiel hosten")); | ||||
|         hostButton.setPreferredSize(new Vector3f(120, 40, 0)); | ||||
|         hostButton.addClickCommands(source -> { | ||||
|             closeCreateGameMenu();      // Schließt das Menü | ||||
|             app.startTestWorld();       // Starte die TestWorld im selben Fenster | ||||
|         }); | ||||
|  | ||||
|         // "Beitreten"-Button | ||||
|         Button joinButton = buttonContainer.addChild(new Button("Beitreten")); | ||||
|         joinButton.setPreferredSize(new Vector3f(120, 40, 0)); | ||||
|         // Placeholder für die Beitrittslogik | ||||
|  | ||||
|         // 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); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird. | ||||
|      */ | ||||
|     private void goBackToStartMenu() { | ||||
|         closeCreateGameMenu();          // Schließt das Menü | ||||
|         StartMenu.createStartMenu(app); // Zeige das Startmenü | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Entfernt das CreateGameMenu und dessen Hintergrund. | ||||
|      */ | ||||
|     private void closeCreateGameMenu() { | ||||
|         app.getGuiNode().detachChild(menuContainer); // Entfernt den Menü-Container | ||||
|         app.getGuiNode().detachChild(background);    // Entfernt das Hintergrundbild | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,124 @@ | ||||
| //////////////////////////////////////// | ||||
| // 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.renderer.queue.RenderQueue.ShadowMode; | ||||
| import com.jme3.scene.Geometry; | ||||
| import com.jme3.scene.Node; | ||||
| import com.jme3.scene.Spatial; | ||||
| import com.jme3.scene.shape.Box; | ||||
|  | ||||
| import pp.monopoly.client.MonopolyApp; | ||||
| import pp.monopoly.game.server.PlayerColor; | ||||
| import pp.monopoly.model.Board; | ||||
| import pp.monopoly.model.Figure; | ||||
| import pp.monopoly.model.Rotation; | ||||
| import static pp.util.FloatMath.HALF_PI; | ||||
| import static pp.util.FloatMath.PI; | ||||
|  | ||||
| /** | ||||
|  * The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical | ||||
|  * representation of the ships and shots on the sea map with the underlying data model. | ||||
|  * It extends the {@link BoardSynchronizer} to provide specific synchronization | ||||
|  * logic for the sea map. | ||||
|  */ | ||||
| class GameBoardSynchronizer extends BoardSynchronizer { | ||||
|     private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS | ||||
|     private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md"; | ||||
|     private static final String COLOR = "Color"; //NON-NLS | ||||
|     private static final String FIGURE = "figure"; //NON-NLS | ||||
|  | ||||
|     private final MonopolyApp app; | ||||
|     private final ParticleEffectFactory particleFactory; | ||||
|  | ||||
|     /** | ||||
|      * Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map. | ||||
|      * | ||||
|      * @param app  the Battleship application | ||||
|      * @param root the root node to which graphical elements will be attached | ||||
|      * @param map  the ship map containing the ships and shots | ||||
|      */ | ||||
|     public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) { | ||||
|         super(board, root); | ||||
|         this.app = app; | ||||
|         this.particleFactory = new ParticleEffectFactory(app); | ||||
|         addExisting(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Visits a {@link Battleship} and creates a graphical representation of it. | ||||
|      * The representation is either a 3D model or a simple box depending on the | ||||
|      * type of battleship. | ||||
|      * | ||||
|      * @param ship the battleship to be represented | ||||
|      * @return the node containing the graphical representation of the battleship | ||||
|      */ | ||||
|     public Spatial visit(Figure figure) { | ||||
|         final Node node = new Node(FIGURE); | ||||
|         node.attachChild(createBox(figure)); | ||||
|         // compute the center of the ship in world coordinates | ||||
|         final float x = 1; | ||||
|         final float z = 1; | ||||
|         node.setLocalTranslation(x, 0f, z); | ||||
|         return node; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a simple box to represent a battleship that is not of the "King George V" type. | ||||
|      * | ||||
|      * @param ship the battleship to be represented | ||||
|      * @return the geometry representing the battleship as a box | ||||
|      */ | ||||
|     private Spatial createBox(Figure figure) { | ||||
|         final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f, | ||||
|                                 0.3f, | ||||
|                                 0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f); | ||||
|         final Geometry geometry = new Geometry(FIGURE, box); | ||||
|         geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor())); | ||||
|         geometry.setShadowMode(ShadowMode.CastAndReceive); | ||||
|  | ||||
|         return geometry; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new {@link Material} with the specified color. | ||||
|      * If the color includes transparency (i.e., alpha value less than 1), | ||||
|      * the material's render state is set to use alpha blending, allowing for | ||||
|      * semi-transparent rendering. | ||||
|      * | ||||
|      * @param color the {@link ColorRGBA} to be applied to the material. If the alpha value | ||||
|      *              of the color is less than 1, the material will support transparency. | ||||
|      * @return a {@link Material} instance configured with the specified color and, | ||||
|      * if necessary, alpha blending enabled. | ||||
|      */ | ||||
|     private Material createColoredMaterial(ColorRGBA color) { | ||||
|         final Material material = new Material(app.getAssetManager(), UNSHADED); | ||||
|         if (color.getAlpha() < 1f) | ||||
|             material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); | ||||
|         material.setColor(COLOR, color); | ||||
|         return material; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculates the rotation angle for the specified rotation. | ||||
|      * | ||||
|      * @param rot the rotation of the battleship | ||||
|      * @return the rotation angle in radians | ||||
|      */ | ||||
|     private static float calculateRotationAngle(Rotation rot) { | ||||
|         return switch (rot) { | ||||
|             case RIGHT -> HALF_PI; | ||||
|             case DOWN -> 0f; | ||||
|             case LEFT -> -HALF_PI; | ||||
|             case UP -> PI; | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| package pp.monopoly.client.gui; | ||||
|  | ||||
| import com.jme3.effect.ParticleMesh.Type; | ||||
|  | ||||
| import pp.monopoly.client.MonopolyApp; | ||||
|  | ||||
| /** | ||||
|  * Factory class responsible for creating particle effects used in the game. | ||||
|  * This centralizes the creation of various types of particle emitters. | ||||
|  */ | ||||
| public class ParticleEffectFactory { | ||||
|     private static final int COUNT_FACTOR = 1; | ||||
|     private static final float COUNT_FACTOR_F = 1f; | ||||
|     private static final boolean POINT_SPRITE = true; | ||||
|     private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle; | ||||
|      | ||||
|     private final MonopolyApp app; | ||||
|  | ||||
|     ParticleEffectFactory(MonopolyApp app) { | ||||
|         this.app = app; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,100 @@ | ||||
| package pp.monopoly.client.gui; | ||||
|  | ||||
| import com.jme3.material.Material; | ||||
| import com.jme3.material.RenderState.BlendMode; | ||||
| import com.jme3.math.ColorRGBA; | ||||
| import com.jme3.scene.Geometry; | ||||
| import com.jme3.scene.shape.Quad; | ||||
| import com.simsilica.lemur.Button; | ||||
| import com.simsilica.lemur.Checkbox; | ||||
| import com.simsilica.lemur.Container; | ||||
| import com.simsilica.lemur.Label; | ||||
| import com.simsilica.lemur.Slider; | ||||
| import com.simsilica.lemur.component.QuadBackgroundComponent; | ||||
| import com.simsilica.lemur.style.ElementId; | ||||
|  | ||||
| import pp.dialog.Dialog; | ||||
| import pp.monopoly.client.MonopolyApp; | ||||
|  | ||||
| /** | ||||
|  * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. | ||||
|  */ | ||||
| public class SettingsMenu extends Dialog { | ||||
|     private final MonopolyApp app; | ||||
|     private final Geometry overlayBackground; | ||||
|     private final Container settingsContainer; | ||||
|  | ||||
|     public SettingsMenu(MonopolyApp app) { | ||||
|         super(app.getDialogManager()); | ||||
|         this.app = app; | ||||
|  | ||||
|         // Halbtransparentes Overlay hinzufügen | ||||
|         overlayBackground = createOverlayBackground(); | ||||
|         app.getGuiNode().attachChild(overlayBackground); | ||||
|  | ||||
|         // 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); | ||||
|  | ||||
|         // Effekt-Sound: Slider und Checkbox | ||||
|         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); | ||||
|  | ||||
|         // 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); | ||||
|  | ||||
|         // Beenden-Button | ||||
|         Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button"))); | ||||
|         quitButton.setFontSize(32); | ||||
|         quitButton.addClickCommands(source -> app.stop()); | ||||
|  | ||||
|         // Zentriere das Menü | ||||
|         settingsContainer.setLocalTranslation( | ||||
|             (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, | ||||
|             (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, | ||||
|             1 | ||||
|         ); | ||||
|  | ||||
|         app.getGuiNode().attachChild(settingsContainer); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Erstellt einen halbtransparenten Hintergrund für das Menü. | ||||
|      * | ||||
|      * @return Geometrie des Overlays | ||||
|      */ | ||||
|     private Geometry createOverlayBackground() { | ||||
|         Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); | ||||
|         Geometry overlay = new Geometry("Overlay", quad); | ||||
|         Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); | ||||
|         material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent | ||||
|         material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); | ||||
|         overlay.setMaterial(material); | ||||
|         overlay.setLocalTranslation(0, 0, 0); | ||||
|         return overlay; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Schließt das Menü und entfernt die GUI-Elemente. | ||||
|      */ | ||||
|     @Override | ||||
|     public void close() { | ||||
|         System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe | ||||
|         app.getGuiNode().detachChild(settingsContainer);  // Entferne das Menü | ||||
|         app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay | ||||
|         app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren | ||||
|         app.unblockInputs();                             // Eingaben wieder aktivieren | ||||
|         System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,107 @@ | ||||
| package pp.monopoly.client.gui; | ||||
|  | ||||
| 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.Box; | ||||
| import com.jme3.texture.Texture; | ||||
|  | ||||
| import pp.monopoly.client.MonopolyApp; | ||||
|  | ||||
| /** | ||||
|  * TestWorld zeigt eine einfache Szene mit einem texturierten Quadrat. | ||||
|  * Die Kamera wird durch den CameraController gesteuert. | ||||
|  */ | ||||
| public class TestWorld { | ||||
|  | ||||
|     private final MonopolyApp app; | ||||
|     private CameraController cameraController; // Steuert die Kamera | ||||
|     private Geometry cube; // Spielfigur | ||||
|  | ||||
|     /** | ||||
|      * Konstruktor für TestWorld. | ||||
|      * | ||||
|      * @param app Die Hauptanwendung (MonopolyApp) | ||||
|      */ | ||||
|     public TestWorld(MonopolyApp app) { | ||||
|         this.app = app; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initialisiert die Szene und startet die Kamerabewegung. | ||||
|      */ | ||||
|     public void initializeScene() { | ||||
|         app.getGuiNode().detachAllChildren(); // Entferne GUI | ||||
|         app.getRootNode().detachAllChildren(); // Entferne andere Szenenobjekte | ||||
|  | ||||
|         setSkyColor(); // Setze den Himmel auf hellblau | ||||
|         createBoard(); // Erstelle das Spielfeld | ||||
|         createCube();  // Füge den Würfel hinzu | ||||
|  | ||||
|         // Erstelle den CameraController | ||||
|         cameraController = new CameraController( | ||||
|                 app.getCamera(),           // Die Kamera der App | ||||
|                 Vector3f.ZERO,            // Fokus auf die Mitte des Spielfelds | ||||
|                 5,                        // Radius des Kreises | ||||
|                 3,                        // Höhe der Kamera | ||||
|                 0.5f                      // Geschwindigkeit der Bewegung | ||||
|         ); | ||||
|  | ||||
|         // Füge die Toolbar hinzu | ||||
|         new Toolbar(app, cube); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Aktualisiert die Kameraposition. | ||||
|      * | ||||
|      * @param tpf Zeit pro Frame | ||||
|      */ | ||||
|     public void update(float tpf) { | ||||
|         if (cameraController != null) { | ||||
|             cameraController.update(tpf); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Setzt die Hintergrundfarbe der Szene auf hellblau. | ||||
|      */ | ||||
|     private void setSkyColor() { | ||||
|         app.getViewPort().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f)); // Hellblauer Himmel | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Erstelle das Spielfeld. | ||||
|      */ | ||||
|     private void createBoard() { | ||||
|         // Erstelle ein Quadrat | ||||
|         Box box = new Box(1, 0.01f, 1);  // Dünnes Quadrat für die Textur | ||||
|         Geometry geom = new Geometry("Board", box); | ||||
|  | ||||
|         // Setze das Material mit Textur | ||||
|         Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); | ||||
|         Texture texture = app.getAssetManager().loadTexture("Pictures/board.png"); | ||||
|         mat.setTexture("ColorMap", texture); | ||||
|         geom.setMaterial(mat); | ||||
|  | ||||
|         app.getRootNode().attachChild(geom); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Erstellt den Würfel (Spielfigur) in der Szene. | ||||
|      */ | ||||
|     private void createCube() { | ||||
|         Box box = new Box(0.05f, 0.05f, 0.05f); // Kleinere Größe für Spielfigur | ||||
|         cube = new Geometry("Cube", box); | ||||
|  | ||||
|         // Setze das Material für den Würfel | ||||
|         Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); | ||||
|         mat.setColor("Color", ColorRGBA.Blue); // Blau gefärbter Würfel | ||||
|         cube.setMaterial(mat); | ||||
|  | ||||
|         // Setze den Startpunkt des Würfels | ||||
|         cube.setLocalTranslation(0.8999999f, 0.1f, -0.9f); | ||||
|  | ||||
|         app.getRootNode().attachChild(cube); | ||||
|     } | ||||
| } | ||||
| @@ -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 Toolbar { | ||||
|  | ||||
|     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 Toolbar(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.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/board.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/board.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 857 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 750 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.1 MiB | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/icons/test.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/icons/test.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.2 KiB | 
		Reference in New Issue
	
	Block a user