diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Asset.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Asset.java index 60dfebcb..a24d9d1c 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Asset.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Asset.java @@ -33,11 +33,11 @@ public enum Asset { treeSmall(1.2f), treeBig(1.2f), turboCard, - turboSymbol("Models/turboCard/turboSymbol.j3o", "Models/turboCard/turboCard_diff.j3o"), + turboSymbol("Models/turboCard/turboSymbol.j3o", "Models/turboCard/turboCard_diff.png"), swapCard, - swapSymbol("Models/swapCard/swapSymbol.j3o", "Models/swapCard/swapCard_diff.j3o"), + swapSymbol("Models/swapCard/swapSymbol.j3o", "Models/swapCard/swapCard_diff.png"), shieldCard, - shieldSymbol("Models/shieldCard/shieldSymbol.j3o", "Models/shieldCard/shieldCard_diff.j3o"), + shieldSymbol("Models/shieldCard/shieldSymbol.j3o", "Models/shieldCard/shieldCard_diff.png"), dice ; diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/InputSynchronizer.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/InputSynchronizer.java index 807a37c4..eb920305 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/InputSynchronizer.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/InputSynchronizer.java @@ -27,6 +27,7 @@ import pp.mdga.notification.SelectableCardsNotification; import java.util.List; +import java.util.UUID; public class InputSynchronizer { @@ -39,6 +40,11 @@ public class InputSynchronizer { private CardControl hoverCard; private PieceControl hoverPiece; + private boolean clickAllowed = true; + + private boolean isRotateLeft = false; + private boolean isRotateRight = false; + /** * Constructor initializes the InputSynchronizer with the application context. * Sets up input mappings and listeners for user interactions. @@ -54,6 +60,18 @@ public class InputSynchronizer { setupInput(); } + public void update(float tpf) { + if(isRotateLeft && isRotateRight) { + return; + } + if(isRotateLeft) { + rotationAngle += 180 * tpf; + } + if(isRotateRight) { + rotationAngle -= 180 * tpf; + } + } + /** * Configures input mappings for various actions and binds them to listeners. */ @@ -61,22 +79,22 @@ private void setupInput() { inputManager.addMapping("Settings", new KeyTrigger(KeyInput.KEY_ESCAPE)); inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_E)); + inputManager.addMapping("RotateRightMouse", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); inputManager.addMapping("MouseLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); // Left movement inputManager.addMapping("MouseRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); // Right movement - inputManager.addMapping("MouseVertical", new MouseAxisTrigger(MouseInput.AXIS_Y, false), new MouseAxisTrigger(MouseInput.AXIS_Y, true)); //Mouse Up Down movement inputManager.addMapping("MouseScrollUp", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); // Scroll up inputManager.addMapping("MouseScrollDown", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); // Scroll down inputManager.addMapping("Test", new KeyTrigger(KeyInput.KEY_J)); inputManager.addMapping("Click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); - inputManager.addListener(actionListener, "Settings", "Forward", "RotateRightMouse", "Click", "Test"); + inputManager.addListener(actionListener, "Settings", "Forward", "RotateRightMouse", "Click", "Left", "Right", "Test"); inputManager.addListener(analogListener, "MouseLeft", "MouseRight", "MouseScrollUp", "MouseScrollDown"); } - - private boolean test = false; - + UUID p = null; /** * Handles action-based input events such as key presses and mouse clicks. */ @@ -93,6 +111,10 @@ public void onAction(String name, boolean isPressed, float tpf) { rightMousePressed = isPressed; } if(name.equals("Click") && isPressed) { + if(!clickAllowed) { + return; + } + if (app.getView() instanceof GameView gameView) { DiceControl diceSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), DiceControl.class); CardControl cardLayerSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), CardControl.class); @@ -121,13 +143,40 @@ else if(boardSelect != null) { } - if(name.equals("Test") &&isPressed){ + if (name.equals("Left")) { + isRotateLeft = !isRotateLeft; + } + if (name.equals("Right")) { + isRotateRight = !isRotateRight; + } + if(name.equals("Test2") &&isPressed){ if(app.getView() instanceof GameView gameView){ + + if(p == null) { + p = UUID.randomUUID(); + gameView.getBoardHandler().addPlayer(Color.AIRFORCE,List.of(p,UUID.randomUUID(),UUID.randomUUID(),UUID.randomUUID())); + gameView.getBoardHandler().movePieceStartAnim(p,0); + gameView.getBoardHandler().movePieceAnim(p,0, 8); + } else { + gameView.getBoardHandler().throwBombAnim(p); + //gameView.getBoardHandler().movePieceStartAnim(p,0); + } + // gameView.getGuiHandler().rollRankingResult(Color.AIRFORCE, 1); // gameView.getGuiHandler().rollRankingResult(Color.ARMY, 2); // gameView.getGuiHandler().rollRankingResult(Color.NAVY, 3); // gameView.getGuiHandler().rollRankingResult(Color.CYBER, 4); - gameView.getGuiHandler().showDice(); +// gameView.getGuiHandler().showDice(); +// UUID p1 = UUID.randomUUID(); + +// gameView.getBoardHandler().addPlayer(Color.AIRFORCE,List.of(p1,UUID.randomUUID(),UUID.randomUUID(),UUID.randomUUID())); +// gameView.getBoardHandler().movePieceStartAnim(p1,0); + //gameView.getGuiHandler().drawCard(Color.ARMY); + //gameView.getGuiHandler().addCardOwn(BonusCard.SHIELD); + //gameView.getGuiHandler().playCardOwn(BonusCard.SHIELD); + + + } } } @@ -302,4 +351,12 @@ public void setRotation(float rotationAngle){ public int getScroll() { return scrollValue; } + + public void setClickAllowed(boolean allowed) { + clickAllowed = allowed; + } + + public boolean isClickAllowed() { + return clickAllowed; + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java index 9755026c..518feb52 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java @@ -9,7 +9,7 @@ import pp.mdga.client.view.*; import javax.imageio.ImageIO; -import java.awt.GraphicsEnvironment; +import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -45,19 +45,19 @@ public class MdgaApp extends SimpleApplication { private MdgaState state = null; /** Scale for rendering images. */ - private float imageScale = prefs.getInt("scale", 1); + private final float imageScale = prefs.getInt("scale", 1); /** The main menu view. */ - private MdgaView mainView; + private MainView mainView; /** The lobby view. */ - private MdgaView lobbyView; + private LobbyView lobbyView; /** The game view. */ - private MdgaView gameView; + private GameView gameView; /** The ceremony view. */ - private MdgaView ceremonyView; + private CeremonyView ceremonyView; /** The client game logic. */ private final ClientGameLogic clientGameLogic; @@ -80,15 +80,29 @@ public MdgaApp() { public static void main(String[] args) { AppSettings settings = new AppSettings(true); settings.setSamples(128); - settings.setWidth(prefs.getInt("width", 1280)); - settings.setHeight(prefs.getInt("height", 720)); + + if(prefs.getBoolean("fullscreen", false)) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int screenWidth = (int) screenSize.getWidth(); + int screenHeight = (int) screenSize.getHeight(); + + settings.setResolution(screenWidth, screenHeight); + + settings.setFullscreen(true); + } else { + settings.setWidth(prefs.getInt("width", 1280)); + settings.setHeight(prefs.getInt("height", 720)); + } + settings.setCenterWindow(true); settings.setVSync(false); settings.setTitle("MDGA"); + settings.setVSync(true); MdgaApp app = new MdgaApp(); app.setSettings(settings); app.setShowSettings(false); app.setPauseOnLostFocus(false); + app.setDisplayStatView(false); app.start(); } @@ -127,6 +141,7 @@ public void simpleUpdate(float tpf) { view.update(tpf); acousticHandler.update(); notificationSynchronizer.update(); + inputSynchronizer.update(tpf); } /** @@ -252,30 +267,60 @@ public ServerConnection getNetworkSupport(){ return networkConnection; } - public void updateResolution(int width, int height, float imageFactor) { - prefs.putInt("width", width); - prefs.putInt("height", height); - prefs.putFloat("scale", imageFactor); + public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) { + if(isFullscreen) { + int baseWidth = 1280; + int baseHeight = 720; + float baseAspectRatio = (float) baseWidth / baseHeight; + float newAspectRatio = (float) width / height; - try { - restartApp(); - } catch (Exception e) { - //nothing + float scaleFactor = Math.max((float) width / baseWidth, (float) height / baseHeight); + + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int screenWidth = (int) screenSize.getWidth(); + int screenHeight = (int) screenSize.getHeight(); + settings.setResolution(screenWidth, screenHeight); + settings.setFullscreen(true); + + prefs.putFloat("scale", scaleFactor); + prefs.putBoolean("fullscreen", true); + } else { + prefs.putInt("width", width); + prefs.putInt("height", height); + prefs.putFloat("scale", imageFactor); + prefs.putBoolean("fullscreen", false); } } - public static void restartApp() throws IOException { - String javaBin = System.getProperty("java.home") + "/bin/java"; - String classPath = System.getProperty("java.class.path"); - String className = System.getProperty("sun.java.command"); + public static void restartApp() { + try { + String javaBin = System.getProperty("java.home") + "/bin/java"; + String classPath = System.getProperty("java.class.path"); + String className = System.getProperty("sun.java.command"); - ProcessBuilder builder = new ProcessBuilder( - javaBin, "-cp", classPath, className - ); + ProcessBuilder builder = new ProcessBuilder( + javaBin, "-cp", classPath, className + ); - builder.start(); + builder.start(); - System.exit(0); + System.exit(0); + } catch (Exception e) { + throw new RuntimeException("restart failed"); + } + } + + public void afterGameCleanup() { + MainView main = (MainView) mainView; + + main.getJoinDialog().disconnect(); + main.getHostDialog().shutdownServer(); + + ceremonyView.afterGameCleanup(); + } + + public GameView getGameView(){ + return gameView; } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/ModelSynchronizer.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/ModelSynchronizer.java index 0b26a305..429b9ade 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/ModelSynchronizer.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/ModelSynchronizer.java @@ -145,4 +145,8 @@ public void enter(MdgaState state) { public void setSwap(boolean swap){ this.swap = swap; } + + public void force() { + + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java index 0ffe9d44..8578b46e 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/NotificationSynchronizer.java @@ -1,5 +1,6 @@ package pp.mdga.client; +import pp.mdga.client.acoustic.MdgaSound; import pp.mdga.client.board.BoardHandler; import pp.mdga.client.gui.GuiHandler; import pp.mdga.client.view.CeremonyView; @@ -19,11 +20,6 @@ public class NotificationSynchronizer { this.app = app; } - public void addTestNotification(Notification n) { - notifications.add(n); - handleGame(n); - } - public void update() { Notification n = app.getGameLogic().getNotification(); while (n != null) { @@ -71,14 +67,15 @@ private void handleLobby(Notification notification) { if (notification instanceof TskSelectNotification n) { lobbyView.setTaken(n.getColor(), true, n.isSelf(), n.getName()); } else if (notification instanceof StartDialogNotification) { + app.afterGameCleanup(); app.enter(MdgaState.MAIN); } else if (notification instanceof TskUnselectNotification n) { lobbyView.setTaken(n.getColor(), false, false, null); } else if(notification instanceof LobbyReadyNotification lobbyReadyNotification) { lobbyView.setReady(lobbyReadyNotification.getColor(), lobbyReadyNotification.isReady()); } else if (notification instanceof GameNotification n) { + app.getGameView().setOwnColor(n.getOwnColor()); app.enter(MdgaState.GAME); - ((GameView) app.getView()).setOwnColor(n.getOwnColor()); } else { throw new RuntimeException("notification not expected in lobby: " + notification.getClass().getName()); } @@ -91,10 +88,11 @@ private void handleGame(Notification notification) { ModelSynchronizer modelSynchronizer = app.getModelSynchronize(); if (notification instanceof AcquireCardNotification n) { - guiHandler.addCard(n.getBonusCard()); + guiHandler.addCardOwn(n.getBonusCard()); } else if (notification instanceof ActivePlayerNotification n) { gameView.getGuiHandler().setActivePlayer(n.getColor()); boardHandler.showDice(n.getColor()); + app.getAcousticHandler().playSound(MdgaSound.UI90); } else if (notification instanceof CeremonyNotification ceremonyNotification) { app.enter(MdgaState.CEREMONY); CeremonyView ceremonyView = (CeremonyView) app.getView(); @@ -130,7 +128,7 @@ private void handleGame(Notification notification) { boardHandler.movePieceHomeAnim(home.getPieceId(), home.getHomeIndex()); guiHandler.hideText(); } else if (notification instanceof InterruptNotification) { - app.enter(MdgaState.LOBBY); + gameView.enterInterrupt(); } else if (notification instanceof MovePieceNotification n) { if(n.isMoveStart()) { //StartMove @@ -142,21 +140,17 @@ private void handleGame(Notification notification) { } guiHandler.hideText(); } else if (notification instanceof ThrowPieceNotification n) { - boardHandler.throwPieceAnim(n.getPieceId()); + boardHandler.throwBombAnim(n.getPieceId()); } else if (notification instanceof NoShieldNotification n) { boardHandler.unshieldPiece(n.getPieceId()); } else if (notification instanceof PlayCardNotification n) { - switch(n.getCard()){ - case SWAP -> guiHandler.swap(); - case TURBO -> guiHandler.turbo(); - case SHIELD -> guiHandler.shield(); - default -> throw new RuntimeException("invalid card"); - } + if(n.getColor() == gameView.getOwnColor()) guiHandler.playCardOwn(n.getCard()); + else guiHandler.playCardEnemy(n.getColor(), n.getCard()); } else if (notification instanceof PlayerInGameNotification n) { boardHandler.addPlayer(n.getColor(),n.getPiecesList()); guiHandler.addPlayer(n.getColor(),n.getName()); } else if (notification instanceof ResumeNotification) { - //TODO + gameView.leaveInterrupt(); } else if (notification instanceof RollDiceNotification n) { gameView.getGuiHandler().hideText(); if(n.getColor() == gameView.getOwnColor()){ @@ -174,6 +168,7 @@ private void handleGame(Notification notification) { } else if (notification instanceof ShieldSuppressedNotification n) { boardHandler.suppressShield(n.getPieceId()); } else if (notification instanceof StartDialogNotification) { + app.afterGameCleanup(); app.enter(MdgaState.MAIN); } else if (notification instanceof SwapPieceNotification n) { // boardHandler.swapPieces(n.getFirstPiece(), n.getSecondPiece()); @@ -200,6 +195,7 @@ private void handleGame(Notification notification) { private void handleCeremony(Notification notification) { if (notification instanceof StartDialogNotification) { + app.afterGameCleanup(); app.enter(MdgaState.MAIN); } else { throw new RuntimeException("notification not expected in ceremony: " + notification.getClass().getName()); diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/AcousticHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/AcousticHandler.java index 264197d4..0e69412a 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/AcousticHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/AcousticHandler.java @@ -109,6 +109,23 @@ public void playSound(MdgaSound sound) { case LEAVE: assets.add(new SoundAssetDelayVolume(SoundAsset.UI_SOUND2, 0.6f, 0.0f)); break; + case JET: + assets.add(new SoundAssetDelayVolume(SoundAsset.JET, 1.0f, 0.0f)); + break; + case EXPLOSION: + assets.add(new SoundAssetDelayVolume(SoundAsset.EXPLOSION_1, 1.0f, 4f)); + assets.add(new SoundAssetDelayVolume(SoundAsset.EXPLOSION_2, 1.0f, 4f)); + assets.add(new SoundAssetDelayVolume(SoundAsset.THUNDER, 1.0f, 4f)); + break; + case LOSE: + assets.add(new SoundAssetDelayVolume(SoundAsset.LOSE, 1.0f, 0.0f)); + break; + case BONUS: + assets.add(new SoundAssetDelayVolume(SoundAsset.BONUS, 1.0f, 0.0f)); + break; + case UI90: + assets.add(new SoundAssetDelayVolume(SoundAsset.UI90, 1.0f, 0.0f)); + break; default: break; } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/MdgaSound.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/MdgaSound.java index 78898155..a3f9ba9f 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/MdgaSound.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/MdgaSound.java @@ -31,4 +31,9 @@ public enum MdgaSound { OTHER_CONNECTED, NOT_READY, LEAVE, + JET, + EXPLOSION, + LOSE, + BONUS, + UI90, } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/SoundAsset.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/SoundAsset.java index 24497300..71e4f20a 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/SoundAsset.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/acoustic/SoundAsset.java @@ -28,6 +28,13 @@ enum SoundAsset { POWERUP("powerup.wav"), ROBOT_READY("robotReady.wav"), UNIT_READY("unitReady.wav"), + JET("jet-overhead.wav"), + EXPLOSION_1("exp.ogg"), + EXPLOSION_2("exp2.ogg"), + THUNDER("thunder.ogg"), + UI90("ui90.ogg"), + BONUS("bonus.ogg"), + LOSE("lose.ogg"), CONNECTED("connected.wav"); private final String path; diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/Explosion.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/Explosion.java new file mode 100644 index 00000000..4fb01568 --- /dev/null +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/Explosion.java @@ -0,0 +1,126 @@ +package pp.mdga.client.animation; + +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.control.AbstractControl; +import pp.mdga.client.MdgaApp; + +public class Explosion { + + private final Node rootNode; + private final MdgaApp app; + private final Vector3f location; + private ParticleEmitter fire; + private ParticleEmitter smoke; + + private boolean triggered = false; + + private final Material mat; + + /** + * Konstruktor für die Explosion. + * + * @param app Die Hauptanwendung. + * @param rootNode Der Root-Knoten, an den die Explosion angefügt wird. + * @param location Der Ort der Explosion in World-Koordinaten. + */ + public Explosion(MdgaApp app, Node rootNode, Vector3f location) { + this.app = app; + this.rootNode = rootNode; + this.location = location; + + this.mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md"); + mat.getAdditionalRenderState().setDepthWrite(false); + mat.getAdditionalRenderState().setDepthTest(false); + } + + /** + * Initialisiert den Partikel-Emitter für die Explosion. + */ + private void initializeEmitter() { + fire = new ParticleEmitter("Effect", Type.Triangle,50); + fire.setMaterial(mat); + fire.setStartColor(ColorRGBA.Yellow); + fire.setEndColor(ColorRGBA.Red); + fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0.2f,0.2f,4f)); + fire.getParticleInfluencer().setVelocityVariation(0.4f); + fire.setStartSize(0.1f); + fire.setEndSize(0.8f); + fire.setGravity(0, 0, -0.1f); + fire.setLowLife(0.5f); + fire.setHighLife(2.2f); + fire.setParticlesPerSec(0); + + fire.setLocalTranslation(location); + fire.move(0, 0, 45); + + smoke = new ParticleEmitter("Effect2", Type.Triangle,40); + smoke.setMaterial(mat); + smoke.setImagesX(2); + smoke.setImagesY(2); + smoke.setStartColor(ColorRGBA.DarkGray); + smoke.setEndColor(new ColorRGBA(0.05f, 0.05f, 0.05f, 1)); + smoke.getParticleInfluencer().setInitialVelocity(new Vector3f(0.0f,0.0f,0.7f)); + smoke.getParticleInfluencer().setVelocityVariation(0.5f); + smoke.setStartSize(0.2f); + smoke.setEndSize(0.5f); + smoke.setGravity(0, 0, -0.3f); + smoke.setLowLife(1.2f); + smoke.setHighLife(5.5f); + smoke.setParticlesPerSec(0); + + smoke.setLocalTranslation(location); + smoke.move(0, 0, 45); + } + + /** + * Löst die Explosion aus. + */ + public void trigger() { + if (!triggered) { + triggered = true; + initializeEmitter(); + } + + rootNode.attachChild(fire); + fire.emitAllParticles(); + fire.addControl(new AbstractControl() { + private float elapsedTime = 0; + + @Override + protected void controlUpdate(float tpf) { + elapsedTime += tpf; + if (elapsedTime > 10f) { + rootNode.detachChild(fire); + fire.removeControl(this); + } + } + + @Override + protected void controlRender(com.jme3.renderer.RenderManager rm, com.jme3.renderer.ViewPort vp) {} + }); + + rootNode.attachChild(smoke); + smoke.emitAllParticles(); + smoke.addControl(new AbstractControl() { + private float elapsedTime = 0; + + @Override + protected void controlUpdate(float tpf) { + elapsedTime += tpf; + if (elapsedTime > 10f) { + rootNode.detachChild(smoke); + smoke.removeControl(this); + } + } + + @Override + protected void controlRender(com.jme3.renderer.RenderManager rm, com.jme3.renderer.ViewPort vp) {} + }); + } +} + diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/JetAnimation.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/JetAnimation.java new file mode 100644 index 00000000..fc339041 --- /dev/null +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/animation/JetAnimation.java @@ -0,0 +1,175 @@ +package pp.mdga.client.animation; + +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import pp.mdga.client.Asset; +import pp.mdga.client.MdgaApp; +import pp.mdga.client.acoustic.MdgaSound; +import pp.mdga.client.board.BoardHandler; +import pp.mdga.client.view.GameView; + +import java.util.UUID; + +public class JetAnimation { + + private final MdgaApp app; // Referenz auf die Hauptanwendung + private final Node rootNode; // Root-Knoten, an dem die Animation hängt + private Spatial jetModel; // Das Model des "jet" + private final Vector3f spawnPoint; // Spawnpunkt des Jets + private final Vector3f nodePoint; // Punkt des überflogenen Knotens + private final Vector3f despawnPoint; // Punkt, an dem der Jet despawnt + private final float curveHeight; // Maximale Höhe der Kurve + private final float animationDuration; // Dauer der Animation + private Explosion explosion; + private final UUID id; + + /** + * Konstruktor für die ThrowAnimation-Klasse. + * + * @param app Die Hauptanwendung + * @param rootNode Der Root-Knoten, an dem der Jet angefügt wird + * @param uuid Die UUID des pieces + * @param targetPoint Der Punkt, an dem der Jet spawnt + * @param curveHeight Die maximale Höhe der Flugkurve + * @param animationDuration Die Gesamtdauer der Animation in Sekunden + */ + public JetAnimation(MdgaApp app, Node rootNode, UUID uuid, Vector3f targetPoint, float curveHeight, float animationDuration) { + Vector3f spawnPoint = targetPoint.add(170, 50, 50); + + Vector3f controlPoint = targetPoint.add(new Vector3f(0, 0, -45)); + + Vector3f despawnPoint = targetPoint.add(-100, -100, 40); + + this.app = app; + this.rootNode = rootNode; + this.spawnPoint = spawnPoint; + this.nodePoint = controlPoint; + this.despawnPoint = despawnPoint; + this.curveHeight = curveHeight; + this.animationDuration = animationDuration; + + id = uuid; + + explosion = new Explosion(app, rootNode, nodePoint); + } + + /** + * Startet die Animation. + */ + public void start() { + app.getAcousticHandler().playSound(MdgaSound.JET); + spawnJet(); + animateJet(); + } + + /** + * Spawnt den Jet an der spezifizierten Position. + */ + private void spawnJet() { + jetModel = app.getAssetManager().loadModel(Asset.jet.getModelPath()); + jetModel.setLocalTranslation(spawnPoint); + jetModel.scale(Asset.jet.getSize()); + jetModel.rotate(FastMath.HALF_PI, 0, 0); + jetModel.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md"); + mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(Asset.jet.getDiffPath())); + jetModel.setMaterial(mat); + + rootNode.attachChild(jetModel); + + app.getAcousticHandler().playSound(MdgaSound.EXPLOSION); + } + + /** + * Animiert den Jet entlang einer Kurve und lässt ihn anschließend verschwinden. + */ + private void animateJet() { + Vector3f controlPoint1 = spawnPoint.add(0, curveHeight, 0); + Vector3f controlPoint2 = nodePoint.add(0, curveHeight, 0); + + BezierCurve3f curve = new BezierCurve3f(spawnPoint, controlPoint1, controlPoint2, despawnPoint); + + app.getRootNode().addControl(new AbstractControl() { + private float elapsedTime = 0; + + @Override + protected void controlUpdate(float tpf) { + elapsedTime += tpf; + float progress = elapsedTime / animationDuration; + + if(elapsedTime > 4.2f) { + explosion.trigger(); + } + + if (progress > 1) { + rootNode.detachChild(jetModel); + this.spatial.removeControl(this); + } else { + Vector3f currentPos = curve.interpolate(progress); + Vector3f direction = curve.interpolateDerivative(progress).normalizeLocal(); + jetModel.setLocalTranslation(currentPos); + jetModel.lookAt(currentPos.add(direction), Vector3f.UNIT_Z); + jetModel.rotate(-FastMath.HALF_PI, 0, (float) Math.toRadians(-25)); + } + + if (elapsedTime > 6.0f) { + GameView gameView = (GameView) app.getView(); + BoardHandler boardHandler = gameView.getBoardHandler(); + + boardHandler.throwPieceAnim(id); + } + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + // Wird hier nicht benötigt + } + }); + } + + /** + * Repräsentiert eine 3D-Bezier-Kurve mit vier Kontrollpunkten. + */ + private static class BezierCurve3f { + private final Vector3f p0, p1, p2, p3; + + public BezierCurve3f(Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3) { + this.p0 = p0; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + } + + public Vector3f interpolate(float t) { + float u = 1 - t; + float tt = t * t; + float uu = u * u; + float uuu = uu * u; + float ttt = tt * t; + + Vector3f point = p0.mult(uuu); + point = point.add(p1.mult(3 * uu * t)); + point = point.add(p2.mult(3 * u * tt)); + point = point.add(p3.mult(ttt)); + return point; + } + + public Vector3f interpolateDerivative(float t) { + float u = 1 - t; + float tt = t * t; + + Vector3f derivative = p0.mult(-3 * u * u); + derivative = derivative.add(p1.mult(3 * u * u - 6 * u * t)); + derivative = derivative.add(p2.mult(6 * u * t - 3 * tt)); + derivative = derivative.add(p3.mult(3 * tt)); + return derivative; + } + } +} diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/board/BoardHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/board/BoardHandler.java index a00508e8..318932e8 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/board/BoardHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/board/BoardHandler.java @@ -9,10 +9,11 @@ import com.jme3.scene.control.AbstractControl; import pp.mdga.client.Asset; import pp.mdga.client.MdgaApp; +import pp.mdga.client.acoustic.MdgaSound; import pp.mdga.client.animation.MoveControl; +import pp.mdga.client.animation.JetAnimation; import pp.mdga.client.gui.DiceControl; import pp.mdga.game.Color; -import pp.mdga.game.Piece; import java.util.*; @@ -443,6 +444,7 @@ private void throwPiece(UUID uuid){ // Synchronisation oder Animation pieceControl.rotateInit(); + app.getAcousticHandler().playSound(MdgaSound.LOSE); app.getModelSynchronize().animationEnd(); } @@ -720,10 +722,20 @@ public void movePieceStartAnim(UUID uuid, int moveIndex){ */ public void throwPieceAnim(UUID uuid){ pieces.get(uuid).getSpatial().addControl(new MoveControl( - pieces.get(uuid).getLocation(), - getNextWaitingNode(pieceColor.get(uuid)).getLocation(), - ()->throwPiece(uuid) - )); + pieces.get(uuid).getLocation(), getNextWaitingNode(pieceColor.get(uuid)).getLocation(), ()->throwPiece(uuid)) + ); + } + + /** + * Animates the throwing of a piece to the next available waiting node. + * + * @param uuid the UUID of the piece to animate + */ + public void throwBombAnim(UUID uuid){ + Vector3f targetPoint = pieces.get(uuid).getLocation(); + + JetAnimation anim = new JetAnimation(app, rootNode, uuid, targetPoint, 40, 6); + anim.start(); } /** diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/InterruptDialog.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/InterruptDialog.java index 4fd87803..7b8d63e2 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/InterruptDialog.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/InterruptDialog.java @@ -1,4 +1,43 @@ package pp.mdga.client.dialog; -public class InterruptDialog { +import com.jme3.math.Vector2f; +import com.jme3.scene.Node; +import pp.mdga.client.MdgaApp; +import pp.mdga.client.button.AbstractButton; +import pp.mdga.client.button.ButtonRight; +import pp.mdga.client.button.LabelButton; +import pp.mdga.client.button.MenuButton; +import pp.mdga.client.view.MdgaView; + +public class InterruptDialog extends Dialog { + private ButtonRight forceButton; + + private LabelButton label; + + public InterruptDialog(MdgaApp app, Node node) { + super(app, node); + + forceButton = new ButtonRight(app, node, () -> app.getModelSynchronize().force(), "Erzwingen", 1); + + label = new LabelButton(app, node, "Warte auf Spieler...", new Vector2f(5.5f * 1.5f, 2), new Vector2f(0.5f, 0f), false); + + float offset = 2.8f; + + label.setPos(new Vector2f(0, MenuButton.VERTICAL - offset)); + } + + @Override + protected void onShow() { + if(app.getGameLogic().isHost()) { + forceButton.show(); + } + + label.show(); + } + + @Override + protected void onHide() { + forceButton.hide(); + label.hide(); + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/JoinDialog.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/JoinDialog.java index 067ba3c7..eedd8cb8 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/JoinDialog.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/JoinDialog.java @@ -92,4 +92,16 @@ public void resetPort() { public void connectToServer() { connectServer(); } + + public void disconnect() { + NetworkSupport network = getNetwork(); + if (network != null) { + try { + network.disconnect(); + } catch (Exception e) { + System.err.println("Error while disconnecting: " + e.getMessage()); + } + } + } } + diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/NetworkDialog.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/NetworkDialog.java index 15c680e9..d44de294 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/NetworkDialog.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/NetworkDialog.java @@ -14,6 +14,8 @@ public abstract class NetworkDialog extends Dialog { private String hostname; private int portNumber; private Future connectionFuture; + private MdgaServer serverInstance; + private Thread serverThread; public NetworkDialog(MdgaApp app, Node node, NetworkSupport network) { super(app, node); @@ -28,7 +30,6 @@ public void setPortNumber(int portNumber) { this.portNumber = portNumber; } - protected Object initNetwork() { try { this.network.initNetwork(this.hostname, this.portNumber); @@ -39,25 +40,49 @@ protected Object initNetwork() { } protected void connectServer() { - try { connectionFuture = this.network.getApp().getExecutor().submit(this::initNetwork); } catch (NumberFormatException var2) { throw new NumberFormatException("Port must be a number"); } - } protected void startServer() { - (new Thread(() -> { + serverThread = new Thread(() -> { try { - MdgaServer mdgaServer = new MdgaServer(portNumber); - mdgaServer.run(); + serverInstance = new MdgaServer(portNumber); + serverInstance.run(); } catch (Exception e) { throw new RuntimeException(e); } + }); - })).start(); + serverThread.start(); + } + + public void shutdownServer() { + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.err.println("Thread was interrupted: " + e.getMessage()); + } + + if (serverInstance != null) { + serverInstance.shutdown(); + serverInstance = null; + } + + if (serverThread != null && serverThread.isAlive()) { + serverThread.interrupt(); + try { + serverThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + serverThread = null; + } } public void update(float delta) { @@ -65,14 +90,14 @@ public void update(float delta) { try { this.connectionFuture.get(); } catch (ExecutionException ignored) { - // todo: implement + // TODO: implement } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } - public NetworkSupport getNetwork(){ + public NetworkSupport getNetwork() { return network; } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/VideoSettingsDialog.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/VideoSettingsDialog.java index cc8f39fa..5aa98cfe 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/VideoSettingsDialog.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/dialog/VideoSettingsDialog.java @@ -3,13 +3,20 @@ import com.jme3.math.Vector2f; import com.jme3.scene.Node; import pp.mdga.client.MdgaApp; +import pp.mdga.client.button.AbstractButton; import pp.mdga.client.button.ButtonLeft; import pp.mdga.client.button.ButtonRight; import pp.mdga.client.button.MenuButton; import pp.mdga.client.view.MdgaView; +import java.util.prefs.Preferences; + public class VideoSettingsDialog extends Dialog { + private static Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class); + + private ButtonRight fullscreenButton; private MenuButton backButton; + private ButtonRight restartButton; private ButtonLeft hdButton9; private ButtonLeft fullHdButton9; @@ -29,20 +36,24 @@ public VideoSettingsDialog(MdgaApp app, Node node, MdgaView view) { backButton = new MenuButton(app, node, view::leaveVideoSettings, "Zurück"); - // MenuButton für verschiedene Auflösungen erstellen - hdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(1280, 720, 1.0f), "hd 16:9", 10); - fullHdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(1920, 1080, 2.25f), "full hd 16:9", 10); - wqhdButton9 = new ButtonLeft(app, node, () -> app.updateResolution(2560, 1440, 4.0f), "wqhd 16:9", 10); + restartButton = new ButtonRight(app, node, MdgaApp::restartApp, "Neustart", 1); + + fullscreenButton = new ButtonRight(app, node, () -> updateResolution(0, 0, 0, true), "Vollbild", 1); + + hdButton9 = new ButtonLeft(app, node, () -> updateResolution(1280, 720, 1.0f, false), "hd 16:9", 10); + fullHdButton9 = new ButtonLeft(app, node, () -> updateResolution(1920, 1080, 2.25f, false), "full hd 16:9", 10); + wqhdButton9 = new ButtonLeft(app, node, () -> updateResolution(2560, 1440, 4.0f, false), "wqhd 16:9", 10); - hdButton10 = new ButtonRight(app, node, () -> app.updateResolution(1280, 800, 1.0f), "hd 16:10", 10); - fullHdButton10 = new ButtonRight(app, node, () -> app.updateResolution(1920, 1200, 2.25f), "full hd 16:10", 10); - wqhdButton10 = new ButtonRight(app, node, () -> app.updateResolution(2560, 1600, 4.0f), "wqhd 16:10", 10); + hdButton10 = new ButtonRight(app, node, () -> updateResolution(1280, 800, 1.0f, false), "hd 16:10", 10); + fullHdButton10 = new ButtonRight(app, node, () -> updateResolution(1920, 1200, 2.25f, false), "full hd 16:10", 10); + wqhdButton10 = new ButtonRight(app, node, () -> updateResolution(2560, 1600, 4.0f, false), "wqhd 16:10", 10); float offset = 2.8f; hdButton9.setPos(new Vector2f(hdButton9.getPos().x, MenuButton.VERTICAL - offset)); hdButton10.setPos(new Vector2f(hdButton10.getPos().x, MenuButton.VERTICAL - offset)); + fullscreenButton.setPos(new Vector2f(fullscreenButton.getPos().x, MenuButton.VERTICAL - offset)); offset += 1.5f; fullHdButton9.setPos(new Vector2f(fullHdButton9.getPos().x, MenuButton.VERTICAL - offset)); @@ -68,6 +79,7 @@ protected void onShow() { fullHdButton10.show(); wqhdButton10.show(); + fullscreenButton.show(); backButton.show(); } @@ -83,7 +95,9 @@ protected void onHide() { fullHdButton10.hide(); wqhdButton10.hide(); + fullscreenButton.hide(); backButton.hide(); + restartButton.hide(); } public void update() { @@ -91,4 +105,12 @@ public void update() { return; } } + + public void updateResolution(int width, int height, float imageFactor, boolean isFullscreen) { + if(width != prefs.getInt("width", 1280) || height != prefs.getInt("height", 720) || isFullscreen != prefs.getBoolean("fullscreen", false)) { + restartButton.show(); + } + + app.updateResolution(width, height, imageFactor, isFullscreen); + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardControl.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardControl.java index f07e7e69..46e47ee6 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardControl.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardControl.java @@ -60,7 +60,7 @@ private Node createNum(){ Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); mat.setColor("Color", ColorRGBA.Black); circle.setMaterial(mat); - root.attachChild(circle); +// root.attachChild(circle); BitmapFont guiFont = getApp().getAssetManager().loadFont("Fonts/Gunplay.fnt"); num = new BitmapText(guiFont); num.setSize(0.3f); diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayer.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayer.java index 860e5324..0f2eacbd 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayer.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayer.java @@ -94,7 +94,8 @@ public void update(float tpf) { } public void addSpatial(Spatial card) { - cardBuffer.add(card); + if(root == null) cardBuffer.add(card); + else root.attachChild(card); } public void deleteSpatial(Spatial spatial) { diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayerHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayerHandler.java index 116e0987..2d5c4d2d 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayerHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/CardLayerHandler.java @@ -85,6 +85,19 @@ public void addCard(BonusCard card) { bonusCardControlMap.get(card).setNumCard(newNum); } + public void removeCard(BonusCard card){ + if(bonusCardControlMap.containsKey(card)){ + bonusCardIntegerMap.put(card, bonusCardIntegerMap.get(card) - 1); + + if(bonusCardIntegerMap.get(card) <= 0){ + cardLayer.deleteSpatial(bonusCardControlMap.get(card).getRoot()); + bonusCardIntegerMap.remove(card); + bonusCardControlMap.remove(card); + } + + } + } + public void clearSelectableCards() { for (CardControl control : selectableCards) { control.setSelectable(false); diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/GuiHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/GuiHandler.java index d4128081..c4024fbe 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/GuiHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/GuiHandler.java @@ -74,8 +74,31 @@ public void hideDice() { cardLayerHandler.hideDice(); } - public void addCard(BonusCard card) { + //add own handCard + public void addCardOwn(BonusCard card) { cardLayerHandler.addCard(card); + playerNameHandler.addCard(ownColor); + actionTextHandler.drawCardOwn(ownColor); + } + + public void playCardOwn(BonusCard card){ + getEffectByCard(card); + cardLayerHandler.removeCard(card); + playerNameHandler.removeCard(ownColor); + } + + public void playCardEnemy(Color color, BonusCard card) { + getEffectByCard(card); + playerNameHandler.removeCard(color); + } + + private void getEffectByCard(BonusCard bonus){ + switch(bonus){ + case SWAP -> swap(); + case TURBO -> turbo(); + case SHIELD -> shield(); + default -> throw new RuntimeException("invalid card"); + } } public void clearSelectableCards() { @@ -125,9 +148,11 @@ public void hideText(){ actionTextHandler.hide(); } + //addCard Enemy (DrawCardNotification) public void drawCard(Color color) { - if (ownColor == color) actionTextHandler.drawCardOwn(color); - else actionTextHandler.drawCard(playerNameHandler.getName(color), color); + //Color != ownColor + actionTextHandler.drawCard(playerNameHandler.getName(color), color); + playerNameHandler.addCard(color); } public void finish(Color color){ @@ -141,4 +166,6 @@ public void rollRankingResult(Color color, int eye){ } + + } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/PlayerNameHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/PlayerNameHandler.java index 2d4bdbf7..e5069eae 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/PlayerNameHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/gui/PlayerNameHandler.java @@ -4,23 +4,27 @@ import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.system.AppSettings; import com.jme3.ui.Picture; +import pp.mdga.game.BonusCard; import pp.mdga.game.Color; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - +import java.util.Vector; public class PlayerNameHandler { private final BitmapFont playerFont; private final Node playerNameNode; private final List playerOrder; private final Map colorNameMap; + private final Map colorCardMap; + private final AppSettings appSettings; private final AssetManager assetManager; private Color ownColor; @@ -43,6 +47,7 @@ public PlayerNameHandler(Node guiNode, AssetManager assetManager, AppSettings ap playerNameNode = new Node("player name node"); playerOrder = new ArrayList<>(); colorNameMap = new HashMap<>(); + colorCardMap = new HashMap<>(); this.appSettings = appSettings; this.assetManager = assetManager; } @@ -64,13 +69,38 @@ private void drawPlayers(){ if(!colorNameMap.containsKey(color)) throw new RuntimeException(color + " isn't mapped to a name"); Node nameParent = new Node("nameParent"); - nameParent.attachChild(createName(colorNameMap.get(color), i == 0, color == ownColor)); nameParent.attachChild(createColor(color)); + BitmapText name = createName(colorNameMap.get(color), i == 0, color == ownColor); + nameParent.attachChild(name); + if(colorCardMap.getOrDefault(color, 0) > 0){ + Picture pic = createHandCard(name.getLineWidth()); + nameParent.attachChild(pic); + nameParent.attachChild(createCardNum(colorCardMap.get(color), pic.getWidth(), pic.getLocalTranslation().getX())); + } nameParent.setLocalTranslation(50,appSettings.getWindowHeight()-PADDING_TOP- MARGIN_NAMES *i,0); playerNameNode.attachChild(nameParent); } } + private Spatial createCardNum(int num, float lastWidth, float lastX ) { + BitmapText hudText = new BitmapText(playerFont); + //renderedSize = 45 + hudText.setSize(TEXT_SIZE); + hudText.setColor(NORMAL_COLOR); + hudText.setText(String.valueOf(num)); + hudText.setLocalTranslation(lastX + lastWidth + 20,hudText.getHeight()/2, 0); + return hudText; + } + + private Picture createHandCard(float width) { + Picture pic = new Picture("HUD Picture"); + pic.setImage(assetManager, "./Images/handcard.png", true); + pic.setWidth(IMAGE_SIZE); + pic.setHeight(IMAGE_SIZE); + pic.setPosition(-pic.getWidth()/2 + width + PADDING_LEFT * 2 ,-pic.getHeight()/2); + return pic; + } + private String imagePath(Color color){ String root = "./Images/name_pictures/"; return switch(color){ @@ -93,7 +123,7 @@ private Spatial createColor(Color color) { - private Spatial createName(String name, boolean first, boolean own){ + private BitmapText createName(String name, boolean first, boolean own){ BitmapText hudText = new BitmapText(playerFont); //renderedSize = 45 hudText.setSize(TEXT_SIZE); @@ -124,5 +154,18 @@ public String getName(Color color){ return colorNameMap.get(color); } + public void addCard(Color color){ + colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) + 1); + drawPlayers(); + } + + public void removeCard(Color color){ + if(colorCardMap.containsKey(color)){ + colorCardMap.put(color, colorCardMap.getOrDefault(color, 0) - 1); + if(colorCardMap.get(color) <= 0) colorCardMap.remove(color); + } + drawPlayers(); + } + } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/CeremonyView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/CeremonyView.java index 31bda387..4c2971a3 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/CeremonyView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/CeremonyView.java @@ -206,11 +206,19 @@ public void addCeremonyParticipant(Color color, int pos, String name) { ceremonyButtons.add(button); if(state.equals(SubState.AWARD_CEREMONY)) { + button.hide(); button.show(); } } public void addStatisticsRow(String name, int v1, int v2, int v3, int v4, int v5, int v6) { ceremonyDialog.addStatisticsRow(name, v1, v2, v3, v4, v5, v6); + + ceremonyDialog.hide(); + ceremonyDialog.show(); + } + + public void afterGameCleanup() { + ceremonyDialog.prepare(); } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/GameView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/GameView.java index f28719ac..973327c2 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/GameView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/GameView.java @@ -1,31 +1,16 @@ package pp.mdga.client.view; import com.jme3.post.FilterPostProcessor; -import pp.mdga.client.MdgaState; +import com.jme3.scene.Node; import pp.mdga.client.acoustic.MdgaSound; import pp.mdga.client.board.BoardHandler; import pp.mdga.client.board.CameraHandler; import pp.mdga.client.MdgaApp; import pp.mdga.client.button.ButtonLeft; import pp.mdga.client.button.ButtonRight; +import pp.mdga.client.dialog.InterruptDialog; import pp.mdga.client.gui.GuiHandler; -import pp.mdga.game.BonusCard; import pp.mdga.game.Color; -import pp.mdga.notification.AcquireCardNotification; -import pp.mdga.notification.ActivePlayerNotification; -import pp.mdga.notification.DiceNowNotification; -import pp.mdga.notification.GameNotification; -import pp.mdga.notification.MovePieceNotification; -import pp.mdga.notification.PlayerInGameNotification; -import pp.mdga.notification.RollDiceNotification; -import pp.mdga.notification.SelectableCardsNotification; -import pp.mdga.notification.SelectableMoveNotification; -import pp.mdga.notification.SelectableSwapNotification; -import pp.mdga.notification.ShieldActiveNotification; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; public class GameView extends MdgaView { private BoardHandler boardHandler; @@ -37,26 +22,32 @@ public class GameView extends MdgaView { private Color ownColor = null; + private InterruptDialog interruptDialog; + private FilterPostProcessor fpp; + private Node guiHandlerNode = new Node(); + public GameView(MdgaApp app) { super(app); - leaveButton = new ButtonLeft(app, overlayNode, () -> app.getModelSynchronize().leave(), "Spiel verlassen", 1); + leaveButton = new ButtonLeft(app, settingsNode, () -> app.getModelSynchronize().leave(), "Spiel verlassen", 1); confirmButton = new ButtonRight(app, guiNode, () -> app.getModelSynchronize().confirm(), "Bestätigen", 1); + interruptDialog = new InterruptDialog(app, guiNode); + fpp = new FilterPostProcessor(app.getAssetManager()); this.camera = new CameraHandler(app, fpp); this.boardHandler = new BoardHandler(app, rootNode, fpp); - guiHandler = new GuiHandler(app, guiNode); + guiHandler = new GuiHandler(app, guiHandlerNode); + guiNode.attachChild(guiHandlerNode); } @Override public void onEnter() { - setOwnColor(Color.AIRFORCE); camera.init(ownColor); boardHandler.init(); guiHandler.init(ownColor); @@ -64,13 +55,6 @@ public void onEnter() { app.getViewPort().addProcessor(fpp); app.getAcousticHandler().playSound(MdgaSound.START); - -// guiHandler.addPlayer(Color.AIRFORCE, "Cedric"); -// guiHandler.addPlayer(Color.ARMY, "Ben"); -// guiHandler.addPlayer(Color.CYBER, "Felix"); -// guiHandler.addPlayer(Color.NAVY, "Daniel"); - - } @Override @@ -131,4 +115,26 @@ public void needConfirm() { public void noConfirm() { confirmButton.hide(); } + + public void enterInterrupt() { + enterOverlay(Overlay.INTERRUPT); + + guiNode.detachChild(guiHandlerNode); + app.getGuiNode().attachChild(guiNode); + + app.getInputSynchronize().setClickAllowed(false); + + interruptDialog.show(); + } + + public void leaveInterrupt() { + leaveOverlay(Overlay.INTERRUPT); + + app.getGuiNode().detachChild(guiNode); + guiNode.attachChild(guiHandlerNode); + + app.getInputSynchronize().setClickAllowed(true); + + interruptDialog.hide(); + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/LobbyView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/LobbyView.java index 31c6a3db..f64623fd 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/LobbyView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/LobbyView.java @@ -231,6 +231,10 @@ private void toggleTsk(Color color) { break; } + if(isReady) { + setReady(own, false); + } + switch (taken) { case NOT: app.getModelSynchronize().selectTsk(color); diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MainView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MainView.java index e19fd274..abcd674c 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MainView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MainView.java @@ -1,19 +1,12 @@ package pp.mdga.client.view; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector2f; import com.jme3.scene.Geometry; import pp.mdga.client.MdgaApp; import pp.mdga.client.acoustic.MdgaSound; -import pp.mdga.client.button.AbstractButton; -import pp.mdga.client.button.LabelButton; import pp.mdga.client.dialog.HostDialog; import pp.mdga.client.dialog.JoinDialog; import pp.mdga.client.dialog.StartDialog; -import java.net.Inet4Address; -import java.net.UnknownHostException; - public class MainView extends MdgaView { private enum SubState { HOST, @@ -67,12 +60,12 @@ public void onUpdate(float tpf) { @Override protected void onEnterOverlay(Overlay overlay) { guiNode.detachChild(background); - overlayNode.attachChild(background); + settingsNode.attachChild(background); } @Override protected void onLeaveOverlay(Overlay overlay) { - overlayNode.detachChild(background); + settingsNode.detachChild(background); guiNode.attachChild(background); } @@ -231,5 +224,13 @@ public void back() { break; } } + + public JoinDialog getJoinDialog() { + return joinDialog; + } + + public HostDialog getHostDialog() { + return hostDialog; + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MdgaView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MdgaView.java index e9bb1b65..a16cc2d7 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MdgaView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/view/MdgaView.java @@ -25,7 +25,7 @@ public enum Overlay { protected MdgaApp app; protected Node rootNode = new Node("View Root"); protected Node guiNode = new Node("View Root GUI"); - protected Node overlayNode = new Node("View Root Overlay"); + protected Node settingsNode = new Node("View Root Overlay"); private SettingsButton settingsButton; @@ -42,9 +42,9 @@ public MdgaView(MdgaApp app) { this.app = app; settingsButton = new SettingsButton(app, guiNode, this::enterSettings); - settingsDialog = new SettingsDialog(app, overlayNode, this); - videoSettingsDialog = new VideoSettingsDialog(app, overlayNode, this); - audioSettingsDialog = new AudioSettingsDialog(app, overlayNode, this); + settingsDialog = new SettingsDialog(app, settingsNode, this); + videoSettingsDialog = new VideoSettingsDialog(app, settingsNode, this); + audioSettingsDialog = new AudioSettingsDialog(app, settingsNode, this); } public void enter() { @@ -124,7 +124,7 @@ protected Geometry createBackground(String texturePath) { public void enterSettings() { enterOverlay(Overlay.SETTINGS); - app.getGuiNode().attachChild(overlayNode); + app.getGuiNode().attachChild(settingsNode); settingsDialog.show(); @@ -134,7 +134,7 @@ public void enterSettings() { public void leaveSettings() { leaveOverlay(Overlay.SETTINGS); - app.getGuiNode().detachChild(overlayNode); + app.getGuiNode().detachChild(settingsNode); settingsDialog.hide(); diff --git a/Projekte/mdga/client/src/main/resources/Images/handcard.png b/Projekte/mdga/client/src/main/resources/Images/handcard.png new file mode 100644 index 00000000..6a30c799 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Images/handcard.png differ diff --git a/Projekte/mdga/client/src/main/resources/Images/particle/particle_cir.png b/Projekte/mdga/client/src/main/resources/Images/particle/particle_cir.png new file mode 100644 index 00000000..ef381886 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Images/particle/particle_cir.png differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/bonus.ogg b/Projekte/mdga/client/src/main/resources/Sounds/bonus.ogg new file mode 100644 index 00000000..63a5db34 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/bonus.ogg differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/exp.ogg b/Projekte/mdga/client/src/main/resources/Sounds/exp.ogg new file mode 100644 index 00000000..b9c570c7 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/exp.ogg differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/exp2.ogg b/Projekte/mdga/client/src/main/resources/Sounds/exp2.ogg new file mode 100644 index 00000000..4b04e8c4 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/exp2.ogg differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/jet-overhead.wav b/Projekte/mdga/client/src/main/resources/Sounds/jet-overhead.wav new file mode 100644 index 00000000..32fcee18 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/jet-overhead.wav differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/lose.ogg b/Projekte/mdga/client/src/main/resources/Sounds/lose.ogg new file mode 100644 index 00000000..9fdc99e5 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/lose.ogg differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/thunder.ogg b/Projekte/mdga/client/src/main/resources/Sounds/thunder.ogg new file mode 100644 index 00000000..db30aaec Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/thunder.ogg differ diff --git a/Projekte/mdga/client/src/main/resources/Sounds/ui90.ogg b/Projekte/mdga/client/src/main/resources/Sounds/ui90.ogg new file mode 100644 index 00000000..7a04ef60 Binary files /dev/null and b/Projekte/mdga/client/src/main/resources/Sounds/ui90.ogg differ