edited 'SeaSynchronizer' and 'ShipControl' for Nr. 12

so now the fire on the ship will be displayed, the seasynchronizer handels it,
in the 'ShipControl' the sinking of a sunken ship is implemented
This commit is contained in:
Benjamin Feyer
2024-10-08 21:20:51 +02:00
parent 54d8ad57cb
commit d53e8577d8
2 changed files with 76 additions and 30 deletions

View File

@@ -29,6 +29,11 @@
import pp.battleship.model.ShipMap;
import pp.battleship.model.Shot;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.lang.System.Logger.Level;
import java.util.Timer;
import static java.util.Objects.requireNonNull;
import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI;
@@ -110,15 +115,54 @@ private Spatial handleHit(Shot shot) {
final ParticleEmitter particleEmitter = createHitParticle(shot);
particleEmitter.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
shipNode.attachChild(particleEmitter);
if (ship.isDestroyed()) {
for (int i = 0; i < 50; i++) {
float r = (float) 0.001 * i;
shipNode.move(0, -r, 0);
}
}
final ParticleEmitter fire = createFire(shot);
shipNode.attachChild(fire);
return null;
}
/**
* this method attach fire to the ship, if it is hit
* @param shot the shot, that hit the ship
* @return the Fire
*/
private ParticleEmitter createFire(Shot shot) {
ParticleEmitter hitEffect = new ParticleEmitter("HitEffect", Type.Triangle, 5000);
hitEffect.setMaterial(new Material(app.getAssetManager(), PARTICLE));
hitEffect.setImagesX(2);
hitEffect.setImagesY(2);
hitEffect.setStartColor(ColorRGBA.Orange);
hitEffect.setEndColor(ColorRGBA.Red);
hitEffect.setStartSize(0.1f);
hitEffect.setEndSize(0.1f);
hitEffect.setParticlesPerSec(2);
hitEffect.setLowLife(1f);
hitEffect.setHighLife(1f);
final Node shipNode = requireNonNull((Node) getSpatial(map.findShipAt(shot.getX(), shot.getY())), "Missing ship node");
Vector3f shipNodePos = shipNode.getLocalTranslation();
Vector3f shotWorld = mapToWorldCord(shot.getX(), shot.getY());
Vector3f firePos = shotWorld.subtract(shipNodePos);
if (map.findShipAt(shot.getX(), shot.getY()).getLength() == 2) {
hitEffect.setLocalTranslation(firePos.x, 0.25f, firePos.z);
}
else {
hitEffect.setLocalTranslation(firePos.x, 0.5f, firePos.z);
}
return hitEffect;
}
/**
* this method converts 2d to 3d positions
*
* @param x x-Coordinate
* @param y-Coordinate
* @return the Position as a 3d Vector
*/
private Vector3f mapToWorldCord(int x, int y) {
return new Vector3f(y + 0.5f, 0, x + 0.5f);
}
/**
* this method creates the particles, when the shot misses
*
@@ -175,28 +219,6 @@ private ParticleEmitter createHitParticle(Shot shot) {
return hitEffect;
}
/**
* Creates a cylinder geometry representing the specified shot.
* The appearance of the cylinder depends on whether the shot is a hit or a miss.
*
* @param shot the shot to be represented
* @return the geometry representing the shot
*/
private Geometry createCylinder(Shot shot) {
final ColorRGBA color = shot.isHit() ? HIT_COLOR : SPLASH_COLOR;
final float height = shot.isHit() ? 1.2f : 0.1f;
final Cylinder cylinder = new Cylinder(2, 20, 0.45f, height, true);
final Geometry geometry = new Geometry(SHOT, cylinder);
geometry.setMaterial(createColoredMaterial(color));
geometry.rotate(HALF_PI, 0f, 0f);
// compute the center of the shot in world coordinates
geometry.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
return geometry;
}
/**
* Visits a {@link Battleship} and creates a graphical representation of it.
* The representation is either a 3D model or a simple box depending on the
@@ -213,7 +235,7 @@ public Spatial visit(Battleship ship) {
final float x = 0.5f * (ship.getMinY() + ship.getMaxY() + 1f);
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
node.setLocalTranslation(x, 0f, z);
node.addControl(new ShipControl(ship));
node.addControl(new ShipControl(ship, map));
return node;
}
@@ -271,6 +293,7 @@ private Spatial createSubmarine(Battleship ship) {
final Spatial model = app.getAssetManager().loadModel(SUBMARINE);
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
model.scale(0.25f);
model.move(0, -0.2f, 0);
model.setShadowMode(ShadowMode.CastAndReceive);

View File

@@ -11,9 +11,13 @@
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;
import pp.battleship.model.Battleship;
import pp.battleship.model.ShipMap;
import static java.util.Objects.requireNonNull;
import static pp.util.FloatMath.DEG_TO_RAD;
import static pp.util.FloatMath.TWO_PI;
import static pp.util.FloatMath.sin;
@@ -48,6 +52,18 @@ class ShipControl extends AbstractControl {
*/
private float time;
/**
* this attribute is the ship, this ShipControl controls
*/
private final Battleship ship;
/**
* this CONST represents the sinking height, when the ship will be removed
*/
private static final Float SINKING_HEIGHT = -0.6f;
/**
* Constructs a new ShipControl instance for the specified Battleship.
* The ship's orientation determines the axis of rotation, while its length influences
@@ -55,7 +71,7 @@ class ShipControl extends AbstractControl {
*
* @param ship the Battleship object to control
*/
public ShipControl(Battleship ship) {
public ShipControl(Battleship ship, ShipMap map) {
// Determine the axis of rotation based on the ship's orientation
axis = switch (ship.getRot()) {
case LEFT, RIGHT -> Vector3f.UNIT_X;
@@ -65,6 +81,7 @@ public ShipControl(Battleship ship) {
// Set the cycle duration and amplitude based on the ship's length
cycle = ship.getLength() * 2f;
amplitude = 5f * DEG_TO_RAD / ship.getLength();
this.ship = ship;
}
/**
@@ -77,6 +94,12 @@ public ShipControl(Battleship ship) {
protected void controlUpdate(float tpf) {
// If spatial is null, do nothing
if (spatial == null) return;
if (ship.isDestroyed() && spatial.getLocalTranslation().getY() < SINKING_HEIGHT) { // removes the ship, if it is completely sunk
spatial.getParent().detachChild(spatial);
}
else if (ship.isDestroyed() && spatial.getLocalTranslation().getY() >= SINKING_HEIGHT) { // sink the ship, if it's not completely sunk
spatial.move(0, tpf * 0.1f * -1, 0);
}
// Update the time within the oscillation cycle
time = (time + tpf) % cycle;