From f248a77c81d74104041ca0fb47fbff33f51b245a Mon Sep 17 00:00:00 2001 From: Johannes Schmelz Date: Mon, 14 Oct 2024 03:38:04 +0200 Subject: [PATCH] states for shell logic implemented --- .../client/gui/MapViewSynchronizer.java | 18 ++++ .../game/client/ShootingAnimationState.java | 93 +++++++++++++++++++ .../game/server/ServerGameLogic.java | 34 ++++++- .../battleship/game/server/ServerState.java | 6 +- .../battleship/game/singlemode/Copycat.java | 7 ++ .../message/client/ClientInterpreter.java | 3 + .../client/ShellAnimationFinishedMessage.java | 10 ++ .../main/java/pp/battleship/model/Shell.java | 47 ++++++++++ .../pp/battleship/model/ShellControl.java | 48 ++++++++++ 9 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 Projekte/battleship/model/src/main/java/pp/battleship/game/client/ShootingAnimationState.java create mode 100644 Projekte/battleship/model/src/main/java/pp/battleship/message/client/ShellAnimationFinishedMessage.java create mode 100644 Projekte/battleship/model/src/main/java/pp/battleship/model/Shell.java create mode 100644 Projekte/battleship/model/src/main/java/pp/battleship/model/ShellControl.java diff --git a/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/MapViewSynchronizer.java b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/MapViewSynchronizer.java index a6075fd..453e1d6 100644 --- a/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/MapViewSynchronizer.java +++ b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/MapViewSynchronizer.java @@ -8,10 +8,12 @@ package pp.battleship.client.gui; import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import pp.battleship.model.Battleship; +import pp.battleship.model.Shell; import pp.battleship.model.Shot; import pp.util.Position; @@ -36,6 +38,7 @@ class MapViewSynchronizer extends ShipMapSynchronizer { // The MapView associated with this synchronizer private final MapView view; + private Shell shell; /** * Constructs a new MapViewSynchronizer for the given MapView. @@ -122,4 +125,19 @@ class MapViewSynchronizer extends ShipMapSynchronizer { private Geometry shipLine(float x1, float y1, float x2, float y2, ColorRGBA color) { return view.getApp().getDraw().makeFatLine(x1, y1, x2, y2, SHIP_DEPTH, color, SHIP_LINE_WIDTH); } + + /** + * + * @param deltaTime + */ + public void update(float deltaTime) { + if (shell != null) { + shell.updatePosition(deltaTime); + drawShell(shell.getCurrentPosition()); + } + } + + private void drawShell(Vector3f position) { + // Methode zum Zeichnen des Geschosses auf der 2D-Karte TODO + } } diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/game/client/ShootingAnimationState.java b/Projekte/battleship/model/src/main/java/pp/battleship/game/client/ShootingAnimationState.java new file mode 100644 index 0000000..2ad0ead --- /dev/null +++ b/Projekte/battleship/model/src/main/java/pp/battleship/game/client/ShootingAnimationState.java @@ -0,0 +1,93 @@ +package pp.battleship.game.client; + +import pp.battleship.message.client.ShellAnimationFinishedMessage; +import pp.battleship.message.server.EffectMessage; +import pp.battleship.model.Shell; + +import java.lang.System.Logger.Level; + +/** + * This class represents the client state during a shooting animation. + * It handles the logic for the animation of a fired shell and ensures + * that the client notifies the server when the animation is complete. + */ +public class ShootingAnimationState extends ClientState { + + // The shell object representing the fired shell's movement + private final Shell shell; + + /** + * Constructs the ShootingAnimationState with the given game logic and shell. + * + * @param logic the game logic instance managing the state + * @param shell the shell object representing the fired projectile + */ + ShootingAnimationState(ClientGameLogic logic, Shell shell) { + super(logic); + this.shell = shell; + } + + /** + * Indicates that the battle scene should be shown in this state. + * + * @return true because the battle view is active during the shooting animation + */ + @Override + public boolean showBattle() { + return true; + } + + /** + * Handles the effect message received from the server. + * Logs the received effect for debugging purposes. + * + * @param msg the effect message received from the server + */ + @Override + void receivedEffect(EffectMessage msg) { + ClientGameLogic.LOGGER.log(Level.INFO, "report effect: {0}", msg); //NON-NLS + // Here, you could implement additional logic to display the effects of the shot, + // like a visual indication of a hit or a miss. + } + + /** + * Called once per frame to update the shell's position and check if it has reached the target. + * If the shell reaches the target, a message is sent to the server. + * + * @param deltaTime time in seconds since the last update call + */ + @Override + public void update(float deltaTime) { + if (shell != null) { + // Update the position of the shell based on the elapsed time + shell.updatePosition(deltaTime); + + // Check if the shell has reached its target + if (shell.isAtTarget()) { + // If the shell has reached the target, notify the server that the animation is complete + sendAnimationCompleteMessage(); + } + } + } + + /** + * Sends a message to the server indicating that the shooting animation has finished. + */ + private void sendAnimationCompleteMessage() { + ShellAnimationFinishedMessage message = new ShellAnimationFinishedMessage(); + // Send the message to the server via the game's logic communication system + logic.send(message); + logic.setState(new BattleState(logic, true)); + ClientGameLogic.LOGGER.log(Level.INFO, "Shell animation complete, message sent to server."); + } + + /** + * Optionally, you can add an entry method if there is any setup that needs to happen when entering the state. + * By default, this is empty. + */ + @Override + void entry() { + super.entry(); // Call the parent entry method + ClientGameLogic.LOGGER.log(Level.INFO, "Entered ShootingAnimationState."); + } +} diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerGameLogic.java b/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerGameLogic.java index b2c6dfc..f0db4c1 100644 --- a/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerGameLogic.java +++ b/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerGameLogic.java @@ -9,8 +9,8 @@ package pp.battleship.game.server; import pp.battleship.BattleshipConfig; import pp.battleship.message.client.ClientInterpreter; -import pp.battleship.message.client.ClientMessage; import pp.battleship.message.client.MapMessage; +import pp.battleship.message.client.ShellAnimationFinishedMessage; import pp.battleship.message.client.ShootMessage; import pp.battleship.message.server.EffectMessage; import pp.battleship.message.server.GameDetails; @@ -36,6 +36,7 @@ public class ServerGameLogic implements ClientInterpreter { private final BattleshipConfig config; private final List players = new ArrayList<>(2); private final Set readyPlayers = new HashSet<>(); + private Set playersFinishedShellAnimation = new HashSet<>(); private final ServerSender serverSender; private Player activePlayer; private ServerState state = ServerState.WAIT; @@ -52,7 +53,7 @@ public class ServerGameLogic implements ClientInterpreter { } /** - * Returns the state of the game. + * Returns the state of the game. */ ServerState getState() { return state; @@ -240,6 +241,10 @@ public class ServerGameLogic implements ClientInterpreter { */ void shoot(Player p, IntPoint pos) { if (p != activePlayer) return; + + setState(ServerState.SHELL_IN_FLIGHT); + // setState(ServerState.BATTLE); + final Player otherPlayer = getOpponent(activePlayer); final Battleship selectedShip = otherPlayer.getMap().findShipAt(pos); if (selectedShip == null) { @@ -269,4 +274,29 @@ public class ServerGameLogic implements ClientInterpreter { } } } + + /** + * Handles the reception of ShellAnimationFinishedMessage. + * This method is called when a client signals that its shell animation is complete. + * + * @param msg the received ShellAnimationFinishedMessage + * @param from the ID of the sender client + */ + @Override + public void received(ShellAnimationFinishedMessage msg, int from) { + // Add the player to the set of players who have finished the animation + playersFinishedShellAnimation.add(from); + + // Check if both players have finished the shell animation + if (playersFinishedShellAnimation.size() == 2) { + // Clear the set of players who have finished the animation for the next shot + playersFinishedShellAnimation.clear(); + + // Transition back to the BATTLE state + setState(ServerState.BATTLE); + + // Log the completion of the shell animation + LOGGER.log(Level.INFO, "Both players finished shell animation. Returning to BATTLE state."); + } + } } diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerState.java b/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerState.java index 507aa7a..e4e494a 100644 --- a/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerState.java +++ b/Projekte/battleship/model/src/main/java/pp/battleship/game/server/ServerState.java @@ -29,5 +29,9 @@ enum ServerState { /** * The game has ended because all the ships of one player have been destroyed. */ - GAME_OVER + GAME_OVER, + /** + * The games is frozen as long as the shell animation is running + */ + SHELL_IN_FLIGHT } diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/game/singlemode/Copycat.java b/Projekte/battleship/model/src/main/java/pp/battleship/game/singlemode/Copycat.java index f6e89be..eb21c74 100644 --- a/Projekte/battleship/model/src/main/java/pp/battleship/game/singlemode/Copycat.java +++ b/Projekte/battleship/model/src/main/java/pp/battleship/game/singlemode/Copycat.java @@ -10,6 +10,7 @@ package pp.battleship.game.singlemode; import pp.battleship.message.client.ClientInterpreter; import pp.battleship.message.client.ClientMessage; import pp.battleship.message.client.MapMessage; +import pp.battleship.message.client.ShellAnimationFinishedMessage; import pp.battleship.message.client.ShootMessage; import pp.battleship.model.Battleship; @@ -72,4 +73,10 @@ class Copycat implements ClientInterpreter { private static Battleship copy(Battleship ship) { return new Battleship(ship.getLength(), ship.getX(), ship.getY(), ship.getRot()); } + + @Override + public void received(ShellAnimationFinishedMessage shellAnimationFinishedMessage, int from) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'received'"); + } } diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ClientInterpreter.java b/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ClientInterpreter.java index 6a50c1d..bc5974d 100644 --- a/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ClientInterpreter.java +++ b/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ClientInterpreter.java @@ -26,4 +26,7 @@ public interface ClientInterpreter { * @param from the connection ID from which the message was received */ void received(MapMessage msg, int from); + + // TODO + void received(ShellAnimationFinishedMessage shellAnimationFinishedMessage, int from); } diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ShellAnimationFinishedMessage.java b/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ShellAnimationFinishedMessage.java new file mode 100644 index 0000000..dba92d2 --- /dev/null +++ b/Projekte/battleship/model/src/main/java/pp/battleship/message/client/ShellAnimationFinishedMessage.java @@ -0,0 +1,10 @@ +package pp.battleship.message.client; + +public class ShellAnimationFinishedMessage extends ClientMessage{ + + @Override + public void accept(ClientInterpreter interpreter, int from) { + interpreter.received(this, from); + } + +} diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/model/Shell.java b/Projekte/battleship/model/src/main/java/pp/battleship/model/Shell.java new file mode 100644 index 0000000..c0d488c --- /dev/null +++ b/Projekte/battleship/model/src/main/java/pp/battleship/model/Shell.java @@ -0,0 +1,47 @@ +package pp.battleship.model; + +import com.jme3.math.Vector3f; + +public class Shell { + private Vector3f startPosition; + private Vector3f targetPosition; + private Vector3f currentPosition; + private float speed; + private boolean isAtTarget; + + public Shell(Vector3f startPosition, Vector3f targetPosition, float speed) { + this.startPosition = startPosition; + this.targetPosition = targetPosition; + this.currentPosition = new Vector3f(startPosition); + this.speed = speed; + this.isAtTarget = true; + } + + // Aktualisiert die Position des Geschosses basierend auf der verstrichenen Zeit + public void updatePosition(float deltaTime) { + if (!isAtTarget) { + // Berechne die Richtung des Geschosses + Vector3f direction = targetPosition.subtract(currentPosition).normalize(); + // Berechne die Bewegung basierend auf der Geschwindigkeit und der verstrichenen Zeit + Vector3f movement = direction.mult(speed * deltaTime); + currentPosition.addLocal(movement); + + // Prüfe, ob das Geschoss das Ziel erreicht hat + if (currentPosition.distance(targetPosition) < speed * deltaTime) { + currentPosition.set(targetPosition); + isAtTarget = true; + } + } + } + + // Gibt die aktuelle Position des Geschosses zurück + public Vector3f getCurrentPosition() { + return currentPosition; + } + + // Überprüft, ob das Geschoss das Ziel erreicht hat + public boolean isAtTarget() { + return isAtTarget; + } +} + diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/model/ShellControl.java b/Projekte/battleship/model/src/main/java/pp/battleship/model/ShellControl.java new file mode 100644 index 0000000..a4c8c45 --- /dev/null +++ b/Projekte/battleship/model/src/main/java/pp/battleship/model/ShellControl.java @@ -0,0 +1,48 @@ +package pp.battleship.model; + +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; + +public class ShellControl extends AbstractControl { + + private Shell shell; // Das Shell-Objekt, das die Bewegung des Geschosses enthält + + public ShellControl(Shell shell) { + this.shell = shell; + } + + // Die Methode wird in jedem Frame aufgerufen, um die Logik zu aktualisieren + @Override + protected void controlUpdate(float deltaTime) { + if (shell != null) { + // Aktualisiere die Position des Geschosses basierend auf der verstrichenen Zeit + shell.updatePosition(deltaTime); + + // Setze die neue Position des Geschosses im 3D-Raum + spatial.setLocalTranslation(shell.getCurrentPosition()); + + // Optionale Animation oder Effekte hinzufügen (z.B. Rauch oder Funkenflug) + // addParticleEffects(); + } + } + + + // Setze das Shell-Objekt neu, um es während des Spiels zu ändern + public void setShell(Shell shell) { + this.shell = shell; + } + + // Gibt das aktuell verwendete Shell-Objekt zurück + public Shell getShell() { + return this.shell; + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + // TODO Auto-generated method stub + } +} +