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:
@@ -29,6 +29,11 @@
|
|||||||
import pp.battleship.model.ShipMap;
|
import pp.battleship.model.ShipMap;
|
||||||
import pp.battleship.model.Shot;
|
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 java.util.Objects.requireNonNull;
|
||||||
import static pp.util.FloatMath.HALF_PI;
|
import static pp.util.FloatMath.HALF_PI;
|
||||||
import static pp.util.FloatMath.PI;
|
import static pp.util.FloatMath.PI;
|
||||||
@@ -110,15 +115,54 @@ private Spatial handleHit(Shot shot) {
|
|||||||
final ParticleEmitter particleEmitter = createHitParticle(shot);
|
final ParticleEmitter particleEmitter = createHitParticle(shot);
|
||||||
particleEmitter.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
|
particleEmitter.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
|
||||||
shipNode.attachChild(particleEmitter);
|
shipNode.attachChild(particleEmitter);
|
||||||
if (ship.isDestroyed()) {
|
final ParticleEmitter fire = createFire(shot);
|
||||||
for (int i = 0; i < 50; i++) {
|
shipNode.attachChild(fire);
|
||||||
float r = (float) 0.001 * i;
|
|
||||||
shipNode.move(0, -r, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
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
|
* this method creates the particles, when the shot misses
|
||||||
*
|
*
|
||||||
@@ -175,28 +219,6 @@ private ParticleEmitter createHitParticle(Shot shot) {
|
|||||||
return hitEffect;
|
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.
|
* 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
|
* 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 x = 0.5f * (ship.getMinY() + ship.getMaxY() + 1f);
|
||||||
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
|
final float z = 0.5f * (ship.getMinX() + ship.getMaxX() + 1f);
|
||||||
node.setLocalTranslation(x, 0f, z);
|
node.setLocalTranslation(x, 0f, z);
|
||||||
node.addControl(new ShipControl(ship));
|
node.addControl(new ShipControl(ship, map));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,6 +293,7 @@ private Spatial createSubmarine(Battleship ship) {
|
|||||||
final Spatial model = app.getAssetManager().loadModel(SUBMARINE);
|
final Spatial model = app.getAssetManager().loadModel(SUBMARINE);
|
||||||
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
|
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
|
||||||
model.scale(0.25f);
|
model.scale(0.25f);
|
||||||
|
model.move(0, -0.2f, 0);
|
||||||
|
|
||||||
model.setShadowMode(ShadowMode.CastAndReceive);
|
model.setShadowMode(ShadowMode.CastAndReceive);
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,13 @@
|
|||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
import pp.battleship.model.Battleship;
|
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.DEG_TO_RAD;
|
||||||
import static pp.util.FloatMath.TWO_PI;
|
import static pp.util.FloatMath.TWO_PI;
|
||||||
import static pp.util.FloatMath.sin;
|
import static pp.util.FloatMath.sin;
|
||||||
@@ -48,6 +52,18 @@ class ShipControl extends AbstractControl {
|
|||||||
*/
|
*/
|
||||||
private float time;
|
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.
|
* Constructs a new ShipControl instance for the specified Battleship.
|
||||||
* The ship's orientation determines the axis of rotation, while its length influences
|
* 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
|
* @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
|
// Determine the axis of rotation based on the ship's orientation
|
||||||
axis = switch (ship.getRot()) {
|
axis = switch (ship.getRot()) {
|
||||||
case LEFT, RIGHT -> Vector3f.UNIT_X;
|
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
|
// Set the cycle duration and amplitude based on the ship's length
|
||||||
cycle = ship.getLength() * 2f;
|
cycle = ship.getLength() * 2f;
|
||||||
amplitude = 5f * DEG_TO_RAD / ship.getLength();
|
amplitude = 5f * DEG_TO_RAD / ship.getLength();
|
||||||
|
this.ship = ship;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,6 +94,12 @@ public ShipControl(Battleship ship) {
|
|||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
// If spatial is null, do nothing
|
// If spatial is null, do nothing
|
||||||
if (spatial == null) return;
|
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
|
// Update the time within the oscillation cycle
|
||||||
time = (time + tpf) % cycle;
|
time = (time + tpf) % cycle;
|
||||||
|
|||||||
Reference in New Issue
Block a user