diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/BoardAppState.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/BoardAppState.java index 2196dda..4ef3ad7 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/BoardAppState.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/BoardAppState.java @@ -8,6 +8,7 @@ import com.jme3.effect.ParticleMesh; import com.jme3.effect.shapes.EmitterSphereShape; import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; @@ -19,6 +20,8 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Cylinder; +import com.jme3.scene.shape.Sphere; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.shadow.EdgeFilteringMode; import com.jme3.texture.Texture; @@ -26,6 +29,8 @@ import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; import pp.monopoly.client.gui.BobTheBuilder; +import pp.monopoly.client.gui.CameraController; +import pp.monopoly.client.gui.CameraInputHandler; import pp.monopoly.client.gui.Toolbar; import pp.monopoly.model.Board; import pp.monopoly.client.gui.FigureControl; @@ -74,6 +79,15 @@ public class BoardAppState extends MonopolyAppState { private Vector3f currentTarget = new Vector3f(-10f,0,-10f); + private float modelHeight = -5f; + private final float targetHeight = 0f; + private final float animationSpeed = 0.01389f; + private Node modelNode; + private boolean startAnimation = false; + private CameraController cameraController; + private CameraInputHandler cameraInputHandler; + + /** * Initializes the state by setting up the sky, lights, and other visual components. * This method is called when the state is first attached to the state manager. @@ -84,12 +98,16 @@ public class BoardAppState extends MonopolyAppState { @Override public void initialize(AppStateManager stateManager, Application application) { super.initialize(stateManager, application); + + // Initialisiere den CameraController zuerst + cameraController = new CameraController(getApp().getCamera(), 25, 40); + + // Danach den CameraInputHandler mit dem initialisierten CameraController + cameraInputHandler = new CameraInputHandler(cameraController, getApp().getInputManager()); + popUpManager = new PopUpManager(getApp()); viewNode.attachChild(sceneNode); - //TODO remove this only for camera testing - adjustCamera(); - setupLights(); setupSky(); } @@ -114,30 +132,6 @@ public class BoardAppState extends MonopolyAppState { } getApp().getRootNode().attachChild(viewNode); } - //TODO remove this only for camera testing - private static final float ABOVE_SEA_LEVEL = 10f; - private static final float INCLINATION = 2.5f; - private float cameraAngle; - - /** - * Adjusts the camera position and orientation to create a circular motion around - * the center of the map. This provides a dynamic view of the sea and surrounding environment. - */ - private void adjustCamera() { - final Board board = getGameLogic().getBoard(); - final float mx = 0.5f * board.getWidth(); - final float my = 0.5f * board.getHeight(); - final float radius = 2f * sqrt(mx * mx + my + my); - final float cos = radius * cos(cameraAngle); - final float sin = radius * sin(cameraAngle); - final float x = mx - cos; - final float y = my - sin; - final Camera camera = getApp().getCamera(); - camera.setLocation(new Vector3f(0,10,0)); - camera.lookAt(new Vector3f(getCurrentTarget()), - Vector3f.UNIT_Y); - camera.update(); - } @@ -154,18 +148,7 @@ public class BoardAppState extends MonopolyAppState { } } - /** - * Updates the state each frame, moving the camera to simulate it circling around the map. - * - * @param tpf the time per frame (seconds) - */ - @Override - public void update(float tpf) { - super.update(tpf); - //TODO remove this only for camera testing - cameraAngle += TWO_PI * 0.05f * tpf; - // adjustCamera(); - } + /** * Sets up the lighting for the scene, including directional and ambient lights. @@ -228,6 +211,8 @@ public class BoardAppState extends MonopolyAppState { sceneNode.attachChild(createCardDeck()); sceneNode.attachChild(seaGeo); + + addModelToCenter(sceneNode); // Schneefall hinzufügen addSnowEffect(sceneNode); @@ -282,4 +267,87 @@ public class BoardAppState extends MonopolyAppState { // Emitter zur Szene hinzufügen parentNode.attachChild(snowEmitter); } + + private void addModelToCenter(Node parentNode) { + AssetManager assetManager = getApp().getAssetManager(); + + Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + material.setColor("Diffuse", ColorRGBA.White); + material.setBoolean("UseMaterialColors", true); + + Sphere lowerSphereLeft = new Sphere(32, 32, 0.5f); + Geometry lowerSphereLeftGeom = new Geometry("LowerSphereLeft", lowerSphereLeft); + lowerSphereLeftGeom.setMaterial(material); + lowerSphereLeftGeom.setLocalTranslation(-0.6f - 4f, 0.5f, 0.3f - 5f); + + Sphere lowerSphereRight = new Sphere(32, 32, 0.5f); + Geometry lowerSphereRightGeom = new Geometry("LowerSphereRight", lowerSphereRight); + lowerSphereRightGeom.setMaterial(material); + lowerSphereRightGeom.setLocalTranslation(0.6f - 4f, 0.5f, 0.3f - 5f); + + Cylinder cylinder = new Cylinder(16, 16, 0.4f, 2f, true); + Geometry cylinderGeom = new Geometry("Cylinder", cylinder); + cylinderGeom.setMaterial(material); + cylinderGeom.setLocalTranslation(0f - 4f, 1.5f, 0f - 5f); + cylinderGeom.rotate(FastMath.HALF_PI, 0, 0); + + Sphere upperSphere = new Sphere(32, 32, 0.4f); + Geometry upperSphereGeom = new Geometry("UpperSphere", upperSphere); + upperSphereGeom.setMaterial(material); + upperSphereGeom.setLocalTranslation(0f - 4f, 2.5f, 0f - 5f); + + this.modelNode = new Node("3DModel"); + this.modelNode.attachChild(lowerSphereLeftGeom); + this.modelNode.attachChild(lowerSphereRightGeom); + this.modelNode.attachChild(cylinderGeom); + this.modelNode.attachChild(upperSphereGeom); + + this.modelNode.setLocalTranslation(0, modelHeight, 0); + parentNode.attachChild(this.modelNode); + + PointLight lightLeft = new PointLight(); + lightLeft.setColor(ColorRGBA.Blue); + lightLeft.setPosition(new Vector3f(-0.6f - 4f, 0f, 0.3f - 5f)); + lightLeft.setRadius(2f); + parentNode.addLight(lightLeft); + + PointLight lightRight = new PointLight(); + lightRight.setColor(ColorRGBA.Blue); + lightRight.setPosition(new Vector3f(0.6f - 4f, 0f, 0.3f - 5f)); + lightRight.setRadius(2f); + parentNode.addLight(lightRight); + } + + @Override + public void update(float tpf) { + super.update(tpf); + if (startAnimation && modelHeight < targetHeight) { + modelHeight += animationSpeed * tpf; // Geschwindigkeit basierend auf Zeit pro Frame + if (modelHeight > targetHeight) { + modelHeight = targetHeight; // Zielhöhe nicht überschreiten + startAnimation = false; // Animation beenden + } + updateModelHeight(); // Aktualisiere die Position des Modells + } + } + + private void updateModelHeight() { + if (modelNode == null) { + modelNode = (Node) sceneNode.getChild("3DModel"); + } + if (modelNode != null) { + modelNode.setLocalTranslation(0, modelHeight, 0); // Aktualisiere die Y-Position + } + } + + public void onRollDicePressed() { + System.out.println("onRollDicePressed called"); + if (!startAnimation) { + startAnimation = true; + modelHeight = -5f; // Reset der Höhe + updateModelHeight(); // Stelle sicher, dass das Modell an der Startposition ist + System.out.println("Animation started, startAnimation set to: " + startAnimation); + } + } + } \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java index 718d871..c42cebe 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java @@ -3,64 +3,57 @@ package pp.monopoly.client.gui; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; -/** - * Controls the movement of the camera within the scene. - */ public class CameraController { + public enum CameraMode { + FOCUS_CURRENT_PLAYER, + FOCUS_SELF, + FREECAM + } + private final Camera camera; - private final float height = 25; // Height of the camera above the game board + private CameraMode currentMode = CameraMode.FOCUS_CURRENT_PLAYER; - /** - * Constructor for the CameraController. - * - * @param camera The camera to be controlled - */ - public CameraController(Camera camera) { + private final float height; // Höhe der Kamera + private final float offset; // Versatz zur Spielfeldseite + + public CameraController(Camera camera, float height, float offset) { this.camera = camera; - setPosition(0); - camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + this.height = height; + this.offset = offset; + setMode(currentMode); + } + + public void setMode(CameraMode mode) { + this.currentMode = mode; + updatePosition(0); // Standardmäßig das Startfeld fokussieren } - /** - * Updates the camera's position and orientation. - * - * @param tpf Time per frame - */ public void update(float tpf) { - camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + if (currentMode != CameraMode.FREECAM) { + camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } } - /** - * Sets the camera's position based on the field ID. - * - * @param fieldID The ID of the field to which the camera should move - */ - public void setPosition(int fieldID) { - camera.setLocation(fieldIdToVector(fieldID)); + public void updatePosition(int fieldID) { + Vector3f newPosition = fieldIdToVector(fieldID); + camera.setLocation(newPosition); + if (currentMode != CameraMode.FREECAM) { + camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } } - /** - * Sets the camera's position using specific coordinates. - * - * @param x The X-coordinate of the new camera position - * @param y The Y-coordinate of the new camera position - */ - public void setPosition(float x, float y) { - camera.setLocation(new Vector3f(x, height, y)); - } - - /** - * Maps a field ID to its corresponding position in the game world. - * - * @param fieldID The ID of the field - * @return The position of the field as a {@link Vector3f} - * @throws IllegalArgumentException If the field ID is invalid - */ private Vector3f fieldIdToVector(int fieldID) { - if (fieldID <= 10) return new Vector3f(30, height, 0); - if (fieldID <= 20) return new Vector3f(0, height, 30); - if (fieldID <= 30) return new Vector3f(-30, height, 0); - if (fieldID <= 40) return new Vector3f(0, height, -30); - else throw new IllegalArgumentException(); + switch (currentMode) { + case FOCUS_CURRENT_PLAYER: + if (fieldID <= 10) return new Vector3f(offset, height, 0); + if (fieldID <= 20) return new Vector3f(0, height, offset); + if (fieldID <= 30) return new Vector3f(-offset, height, 0); + return new Vector3f(0, height, -offset); + case FOCUS_SELF: + return new Vector3f(0, height, fieldID <= 20 ? offset : -offset); + case FREECAM: + default: + return new Vector3f(0, height, 0); + } } -} \ No newline at end of file +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraInputHandler.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraInputHandler.java index d494b76..db53128 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraInputHandler.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraInputHandler.java @@ -1,60 +1,31 @@ -//package pp.monopoly.client.gui; -// -//import com.jme3.input.InputManager; -//import com.jme3.input.KeyInput; -//import com.jme3.input.controls.ActionListener; -//import com.jme3.input.controls.KeyTrigger; -// -///** -// * Handhabt die Eingaben für die Kamera. -// */ -//public class CameraInputHandler { -// -// private CameraController cameraController; // Kamera-Controller -// -// /** -// * Konstruktor für den CameraInputHandler. -// * -// * @param cameraController Der Kamera-Controller, der gesteuert werden soll. -// * @param inputManager Der InputManager, um Eingaben zu registrieren. -// */ -// public CameraInputHandler(CameraController cameraController, InputManager inputManager) { -// if (cameraController == null || inputManager == null) { -// throw new IllegalArgumentException("CameraController und InputManager dürfen nicht null sein"); -// } -// this.cameraController = cameraController; -// -// // Mappings für Kamerasteuerung -// inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1)); // Modus 1 -// inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2)); // Modus 2 -// inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3)); // Modus 3 -// -// // Listener für die Kameramodi -// inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam"); -// } -// -// /** -// * ActionListener für die Kamerasteuerung. -// */ -// private final ActionListener actionListener = (name, isPressed, tpf) -> { -// if (!isPressed) return; -// -// // Umschalten der Kamera-Modi basierend auf der Eingabe -// switch (name) { -// case "FocusCurrentPlayer" -> { -// cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER); -// System.out.println("Kameramodus: Fokus auf aktuellen Spieler"); -// } -// case "FocusSelf" -> { -// cameraController.setMode(CameraController.CameraMode.FOCUS_SELF); -// System.out.println("Kameramodus: Fokus auf eigene Figur"); -// } -// case "FreeCam" -> { -// cameraController.setMode(CameraController.CameraMode.FREECAM); -// System.out.println("Kameramodus: Freie Kamera"); -// } -// default -> System.err.println("Unbekannter Kameramodus: " + name); -// } -// }; -//} -// \ No newline at end of file +package pp.monopoly.client.gui; + +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; + +public class CameraInputHandler { + private CameraController cameraController; + + public CameraInputHandler(CameraController cameraController, InputManager inputManager) { + this.cameraController = cameraController; + + // Tasten für die verschiedenen Kameramodi registrieren + inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3)); + + inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam"); + } + + private final ActionListener actionListener = (name, isPressed, tpf) -> { + if (!isPressed) return; + + switch (name) { + case "FocusCurrentPlayer" -> cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER); + case "FocusSelf" -> cameraController.setMode(CameraController.CameraMode.FOCUS_SELF); + case "FreeCam" -> cameraController.setMode(CameraController.CameraMode.FREECAM); + } + }; +} \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java index de25d50..969e28b 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java @@ -20,6 +20,7 @@ import com.simsilica.lemur.event.MouseEventControl; import com.simsilica.lemur.event.MouseListener; import com.simsilica.lemur.style.ElementId; import pp.dialog.Dialog; +import pp.monopoly.client.BoardAppState; import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.gui.popups.Bankrupt; import pp.monopoly.game.server.Player; @@ -282,15 +283,21 @@ public class Toolbar extends Dialog implements GameEventListener { * Handles the dice roll event. */ private void handleDiceRoll() { - ifTopDialog(() -> { - if (!canRollDice) return; - canRollDice = false; - if (endTurnButton != null) endTurnButton.setEnabled(true); - startDiceAnimation(); - app.getGameLogic().send(new RollDice()); - app.getGameLogic().playSound(Sound.BUTTON); - }); - } + ifTopDialog(() -> { + if (!canRollDice) return; + canRollDice = false; + if (endTurnButton != null) endTurnButton.setEnabled(true); + startDiceAnimation(); + app.getGameLogic().send(new RollDice()); + app.getGameLogic().playSound(Sound.BUTTON); + + // Animation in BoardAppState starten + BoardAppState boardAppState = app.getStateManager().getState(BoardAppState.class); + if (boardAppState != null) { + boardAppState.onRollDicePressed(); // Animation starten + } + }); +} private Button createTradeButton() { @@ -307,6 +314,7 @@ public class Toolbar extends Dialog implements GameEventListener { tradeButton.addClickCommands(s -> ifTopDialog(() -> { new ChoosePartner(app).open(); + })); return tradeButton;