From 520b98f6939dfd9b9b95a2ced3c5ffe5136c3d03 Mon Sep 17 00:00:00 2001 From: Yvonne Schmidt Date: Fri, 11 Oct 2024 01:33:52 +0200 Subject: [PATCH] added a sinking effect for damaged ships --- .../client/gui/ShipSinkingControl.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Projekte/battleship/client/src/main/java/pp/battleship/client/gui/ShipSinkingControl.java diff --git a/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/ShipSinkingControl.java b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/ShipSinkingControl.java new file mode 100644 index 0000000..a62c095 --- /dev/null +++ b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/ShipSinkingControl.java @@ -0,0 +1,116 @@ +package pp.battleship.client.gui; + +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; + +/** + * Controls the burning, tilting, and sinking behavior of a battleship. + * The ship will burn and tilt for a specified duration, then sink below the water surface. + */ +public class ShipSinkingControl extends AbstractControl { + + private float elapsedTime = 0f; + private final float burnTiltDuration; + private final float sinkDuration; + private final float sinkDepth; + private final float tiltAngle; + private final Vector3f initialPosition; + private boolean sinkingStarted = false; + + /** + * Constructs a new ShipSinkingControl instance. + * + * @param burnTiltDuration Time in seconds for the ship to burn and tilt on the surface + * @param sinkDuration Time in seconds for the ship to fully sink + * @param sinkDepth Depth below the water to sink the ship + * @param tiltAngle Final tilt angle in degrees + */ + public ShipSinkingControl(float burnTiltDuration, float sinkDuration, float sinkDepth, float tiltAngle) { + this.burnTiltDuration = burnTiltDuration; + this.sinkDuration = sinkDuration; + this.sinkDepth = sinkDepth; + this.tiltAngle = tiltAngle; + this.initialPosition = new Vector3f(); // Placeholder; will be set in controlUpdate + } + + /** + * Overrides controlUpdate in AbstractControl + * regulates the burn and tilt timeframe + * @param tpf time per frame (in seconds) + */ + + @Override + protected void controlUpdate(float tpf) { + if (spatial == null) return; + + elapsedTime += tpf; + + if (elapsedTime < burnTiltDuration) { + float progress = elapsedTime / burnTiltDuration; + + float angleInRadians = FastMath.DEG_TO_RAD * FastMath.interpolateLinear(progress, 0f, -tiltAngle); + Quaternion tiltRotation = new Quaternion().fromAngles(angleInRadians, 0, 0); + spatial.setLocalRotation(tiltRotation); + return; + } + + // Start sinking if it hasn't started yet + if (!sinkingStarted) { + sinkingStarted = true; + // Save the initial position when sinking starts + initialPosition.set(spatial.getLocalTranslation()); + + // Remove the hitEffectNode + Node parentNode = (Node) spatial; + Spatial hitEffects = parentNode.getChild("HitEffectNode"); + if (hitEffects != null) { + parentNode.detachChild(hitEffects); + } + } + + // Calculate the progress of the sinking (0 to 1) + float progress = Math.min((elapsedTime - burnTiltDuration) / sinkDuration, 1f); + + // Apply the tilt angle (remains constant during sinking) + Quaternion tiltRotation = new Quaternion().fromAngles(-FastMath.DEG_TO_RAD * tiltAngle, 0, 0); + spatial.setLocalRotation(tiltRotation); + + // Sink the ship by interpolating the Y position + float currentY = FastMath.interpolateLinear(progress, initialPosition.y, sinkDepth); + spatial.setLocalTranslation(initialPosition.x, currentY, initialPosition.z); + + if (currentY <= sinkDepth) { + Node parentNode = (Node) spatial.getParent(); + if (parentNode != null) { + parentNode.detachChild(spatial); + } + spatial.removeControl(this); + } + } + + /** + * This method is called during the rendering phase, but it does not perform any + * operations in this implementation as the control only influences the spatial's + * transformation, not its rendering process. + * + * @param rm the RenderManager rendering the controlled Spatial (not null) + * @param vp the ViewPort being rendered (not null) + */ + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + // No rendering logic is needed for this control + } + + /** + * Starts the sinking process for the ship. + */ + public void startSinking() { + // Nothing to do here as the control update handles the timing and sequence + } +} \ No newline at end of file