diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java index 3548c76..6d69bac 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java @@ -1,5 +1,7 @@ package pp.monopoly.client.gui; +import java.util.ArrayList; +import java.util.List; import java.util.Timer; import java.util.TimerTask; @@ -10,7 +12,14 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.control.AbstractControl; import pp.monopoly.client.MonopolyApp; -import pp.monopoly.client.gui.popups.*; +import pp.monopoly.client.gui.popups.BuildingPropertyCard; +import pp.monopoly.client.gui.popups.ConfirmTrade; +import pp.monopoly.client.gui.popups.EventCardPopup; +import pp.monopoly.client.gui.popups.FoodFieldCard; +import pp.monopoly.client.gui.popups.GateFieldCard; +import pp.monopoly.client.gui.popups.LooserPopUp; +import pp.monopoly.client.gui.popups.TimeOut; +import pp.monopoly.client.gui.popups.WinnerPopUp; import pp.monopoly.game.server.Player; import pp.monopoly.game.server.PlayerHandler; import pp.monopoly.model.fields.BuildingProperty; @@ -19,7 +28,6 @@ import pp.monopoly.model.fields.GateField; import pp.monopoly.notification.EventCardEvent; import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.PopUpEvent; -import pp.monopoly.notification.Sound; import pp.monopoly.notification.UpdatePlayerView; /** @@ -40,9 +48,9 @@ public class TestWorld implements GameEventListener { */ public TestWorld(MonopolyApp app) { this.app = app; - this.playerHandler = app.getGameLogic().getPlayerHandler(); // Hole den PlayerHandler + this.playerHandler = app.getGameLogic().getPlayerHandler(); app.getGameLogic().addListener(this); - cameraController = new CameraController(app.getCamera()); // Übergebe PlayerHandler + cameraController = new CameraController(app.getCamera()); } /** @@ -86,7 +94,7 @@ public class TestWorld implements GameEventListener { geom.setLocalTranslation(0, -0.1f, 0); com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion(); - rotation.fromAngleAxis(com.jme3.math.FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y); + rotation.fromAngleAxis(FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y); geom.setLocalRotation(rotation); app.getRootNode().attachChild(geom); @@ -109,7 +117,8 @@ public class TestWorld implements GameEventListener { ); model.setLocalScale(0.5f); - Vector3f startPosition = calculateFieldPosition(player.getFieldID(), i); + int playerIndexOnField = calculatePlayerIndexOnField(player.getFieldID(), player.getId()); + Vector3f startPosition = calculateFieldPosition(player.getFieldID(), playerIndexOnField); model.setLocalTranslation(startPosition); model.setName("PlayerFigure_" + player.getId()); @@ -178,72 +187,49 @@ public class TestWorld implements GameEventListener { } private void movePlayerFigure(Player player) { - int fieldID = player.getFieldID(); - int playerIndex = playerHandler.getPlayers().indexOf(player); // Spielerindex holen - Vector3f targetPosition = calculateFieldPosition(fieldID, playerIndex); - + int playerIndexOnField = calculatePlayerIndexOnField(player.getFieldID(), player.getId()); String figureName = "PlayerFigure_" + player.getId(); com.jme3.scene.Spatial figure = app.getRootNode().getChild(figureName); if (figure != null) { - Vector3f startPosition = figure.getLocalTranslation(); - Vector3f cornerPosition = calculateCornerPosition(startPosition, targetPosition); // Berechne Eckpunkt - float animationDuration = 3.0f; // Gesamtdauer der Animation - float[] elapsedTime = {0.0f}; // Verstrichene Zeit + // Berechne das aktuelle Feld basierend auf der Position der Figur + int startFieldID = getFieldIDFromPosition(figure.getLocalTranslation()); + int targetFieldID = player.getFieldID(); - Timer timer = new Timer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - app.enqueue(() -> { - app.getRootNode().addControl(new AbstractControl() { - @Override - protected void controlUpdate(float tpf) { - elapsedTime[0] += tpf; - float progress = Math.min(elapsedTime[0] / animationDuration, 1.0f); + // Bewege die Figur nur, wenn das Ziel-Feld unterschiedlich ist + if (startFieldID != targetFieldID) { + // Verzögerung vor Start der Animation (z.B. 3 Sekunden) + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + // Berechne den Pfad basierend auf den Feld-IDs + List pathPoints = calculatePath(startFieldID, targetFieldID, playerIndexOnField); - Vector3f interpolatedPosition; - if (progress < 0.5f) { - // Erste Hälfte der Animation: Bewegung zur Ecke - float localProgress = progress / 0.5f; // Normiere auf [0, 1] - interpolatedPosition = new Vector3f( - FastMath.interpolateLinear(localProgress, startPosition.x, cornerPosition.x), - FastMath.interpolateLinear(localProgress, startPosition.y, cornerPosition.y), - FastMath.interpolateLinear(localProgress, startPosition.z, cornerPosition.z) - ); - } else { - // Zweite Hälfte der Animation: Bewegung vom Eckpunkt zum Ziel - float localProgress = (progress - 0.5f) / 0.5f; // Normiere auf [0, 1] - interpolatedPosition = new Vector3f( - FastMath.interpolateLinear(localProgress, cornerPosition.x, targetPosition.x), - FastMath.interpolateLinear(localProgress, cornerPosition.y, targetPosition.y), - FastMath.interpolateLinear(localProgress, cornerPosition.z, targetPosition.z) - ); - } - - figure.setLocalTranslation(interpolatedPosition); - - // Animation beenden, wenn sie fertig ist - if (progress >= 1.0f) { - this.setEnabled(false); - app.getRootNode().removeControl(this); - System.out.println("Spieler " + player.getId() + " hat das Ziel erreicht: " + targetPosition); - } - } - - @Override - protected void controlRender(RenderManager rm, ViewPort vp) { - // Keine spezielle Renderlogik notwendig - } - }); - }); - } - }, (long) 2000); // Verzögerung in Millisekunden + // Starte die Animation entlang des Pfads + animateMovementAlongPath(figure, pathPoints); + } + }, 3000); // Verzögerung von 3000ms (3 Sekunden) + } else { + System.out.println("Figur für Spieler " + player.getId() + " bleibt auf dem gleichen Feld."); + } } else { System.err.println("Figur für Spieler " + player.getId() + " nicht gefunden."); } } - + + private int getFieldIDFromPosition(Vector3f position) { + for (int fieldID = 0; fieldID < 40; fieldID++) { + Vector3f fieldPosition = calculateFieldPosition(fieldID, 0); + if (fieldPosition.distance(position) < 0.5f) { // Toleranz für Positionserkennung + return fieldID; + } + } + throw new IllegalArgumentException("Position entspricht keinem gültigen Feld: " + position); + } + + + /** * Berechnet den Eckpunkt basierend auf Start- und Zielposition. * @@ -252,28 +238,120 @@ public class TestWorld implements GameEventListener { * @return Die Position der Ecke, die passiert werden muss. */ private Vector3f calculateCornerPosition(Vector3f startPosition, Vector3f targetPosition) { - if (Math.abs(startPosition.x - targetPosition.x) > Math.abs(startPosition.z - targetPosition.z)) { - // Bewegung entlang der X-Achse zuerst, dann Z-Achse - return new Vector3f(targetPosition.x, 0, startPosition.z); + // Ziel: Immer entlang der Spielfeldkante navigieren + float deltaX = targetPosition.x - startPosition.x; + float deltaZ = targetPosition.z - startPosition.z; + + // Überprüfen, ob Bewegung entlang X oder Z-Koordinate zuerst erfolgen soll + if (deltaX != 0 && deltaZ != 0) { + if (Math.abs(deltaX) > Math.abs(deltaZ)) { + // Bewegung entlang X zuerst + return new Vector3f(targetPosition.x, 0, startPosition.z); + } else { + // Bewegung entlang Z zuerst + return new Vector3f(startPosition.x, 0, targetPosition.z); + } } else { - // Bewegung entlang der Z-Achse zuerst, dann X-Achse - return new Vector3f(startPosition.x, 0, targetPosition.z); + // Bewegung ist bereits entlang einer Achse (keine Ecke erforderlich) + return targetPosition; } } + private List calculatePath(int startFieldID, int targetFieldID, int playerIndex) { + List pathPoints = new ArrayList<>(); + + // Bewegung im Uhrzeigersinn + if (startFieldID < targetFieldID) { + for (int i = startFieldID; i <= targetFieldID; i++) { + // Füge Ecken hinzu, falls sie überschritten werden + if (i == 10 || i == 20 || i == 30 || i == 0) { + pathPoints.add(calculateFieldPosition(i, playerIndex)); + } + } + } else { + // Bewegung über das Ende des Spielfelds hinaus (z.B. von 39 zu 5) + for (int i = startFieldID; i < 40; i++) { + if (i == 10 || i == 20 || i == 30 || i == 0) { + pathPoints.add(calculateFieldPosition(i, playerIndex)); + } + } + for (int i = 0; i <= targetFieldID; i++) { + if (i == 10 || i == 20 || i == 30 || i == 0) { + pathPoints.add(calculateFieldPosition(i, playerIndex)); + } + } + } + + // Füge das Ziel hinzu + pathPoints.add(calculateFieldPosition(targetFieldID, playerIndex)); + + return pathPoints; + } + + + + private int calculatePlayerIndexOnField(int fieldID, int playerID) { + List playersOnField = playerHandler.getPlayers().stream() + .filter(p -> p.getFieldID() == fieldID) + .toList(); + + for (int i = 0; i < playersOnField.size(); i++) { + if (playersOnField.get(i).getId() == playerID) { + return i; + } + } + return 0; + } + + private void animateMovementAlongPath(com.jme3.scene.Spatial figure, List pathPoints) { + float animationDurationPerSegment = 2.5f; // Langsamere Animation (2.5 Sekunden pro Segment) + int[] currentSegment = {0}; + + app.enqueue(() -> { + figure.addControl(new AbstractControl() { + private float elapsedTime = 0.0f; + + @Override + protected void controlUpdate(float tpf) { + if (currentSegment[0] >= pathPoints.size() - 1) { + this.setEnabled(false); // Animation abgeschlossen + return; + } + + elapsedTime += tpf; + float progress = Math.min(elapsedTime / animationDurationPerSegment, 1.0f); + + Vector3f start = pathPoints.get(currentSegment[0]); + Vector3f end = pathPoints.get(currentSegment[0] + 1); + + Vector3f interpolatedPosition = start.interpolateLocal(end, progress); + figure.setLocalTranslation(interpolatedPosition); + + if (progress >= 1.0f) { + elapsedTime = 0.0f; + currentSegment[0]++; + } + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + // Nicht benötigt + } + }); + }); + } + @Override public void receivedEvent(PopUpEvent event) { if (event.msg().equals("Buy")) { - // Erstelle einen Timer, um den Delay umzusetzen Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { - // GUI-Operationen im jMonkey-Thread ausführen app.enqueue(() -> { int field = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID(); Object fieldObject = app.getGameLogic().getBoardManager().getFieldAtIndex(field); - + if (fieldObject instanceof BuildingProperty) { new BuildingPropertyCard(app).open(); } else if (fieldObject instanceof GateField) { @@ -283,14 +361,14 @@ public class TestWorld implements GameEventListener { } }); } - }, 2500); // Verzögerung in Millisekunden + }, 2500); } else if (event.msg().equals("Winner")) { new WinnerPopUp(app).open(); } else if (event.msg().equals("Looser")) { new LooserPopUp(app).open(); } else if (event.msg().equals("timeout")) { new TimeOut(app).open(); - } else if(event.msg().equals("tradeRequest")) { + } else if (event.msg().equals("tradeRequest")) { new ConfirmTrade(app).open(); } } @@ -301,20 +379,14 @@ public class TestWorld implements GameEventListener { timer.schedule(new TimerTask() { @Override public void run() { - app.enqueue(() -> { - app.getGameLogic().playSound(Sound.EVENT_CARD); - new EventCardPopup(app, event.description()).open(); - }); + app.enqueue(() -> new EventCardPopup(app, event.description()).open()); } - }, 2500); // 5 Sekunden Verzögerung für Event-Popups + }, 2500); } - @Override public void receivedEvent(UpdatePlayerView event) { this.playerHandler = app.getGameLogic().getPlayerHandler(); - - // Aktualisiere die Position aller Spielerfiguren for (Player player : playerHandler.getPlayers()) { movePlayerFigure(player); } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java index 7ec2d3e..4a10146 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java @@ -47,7 +47,7 @@ public class DeckHelper{ cards.add(new Card("Du wurdest zur VP gewählt und schmeißt eine Einstandsparty. Zahle 800 EUR", "vp-einstandsparty")); cards.add(new Card("Du hast eine Party veranstaltet und dick Gewinn gemacht. Ziehe 1500 EUR ein", "party-gewinn")); cards.add(new Card("Zur falschen Zeit am falschen Ort. Du musst einen Bergmarsch planen und setzt eine Runde aus.", "bergmarsch")); - cards.add(new Card("Dein Jodel eines Eispenis mit Unterhodenbeleuchtung geht viral. Ziehe 1000 EUR ein", "jodel-eispenis")); + cards.add(new Card("Dein Jodel eines Schneepenis mit Unterhodenbeleuchtung geht viral. Ziehe 1000 EUR ein", "jodel-eispenis")); shuffle(); }