Aufgabe 13
added class Shell for the feature Airstrike added class ShellControl for the feature Airstrike added new Model Bomb to implement the feature Airstrike added README´S to the Models to show the free to use license edited class ShipMap for the feature Airstrike edited class ImpactEffectManager to improve the Fire and Water Particles edited class MapViewSynchronizer for the feature Airstrike edited class BattleState for the feature Airstrike edited class BattleshipApp for the feature Airstrike
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#
|
||||
# Specifies the map used by the opponent in single mode.
|
||||
# Single mode is activated if this property is set.
|
||||
#map.opponent=maps/map2.json
|
||||
map.opponent=maps/map2.json
|
||||
#
|
||||
# Specifies the map used by the player in single mode.
|
||||
# The player must define their own map if this property is not set.
|
||||
|
||||
@@ -145,6 +145,7 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new BattleshipApp().start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.battleship.client.BattleshipApp;
|
||||
import pp.battleship.model.Shot;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
@@ -23,13 +24,15 @@ public class ImpactEffectManager {
|
||||
private static final Logger LOGGER = System.getLogger(ImpactEffectManager.class.getName());
|
||||
|
||||
private Material particleMaterial;
|
||||
private BattleshipApp app;
|
||||
|
||||
/**
|
||||
* Constructor to initialize the asset manager via the main application.
|
||||
*
|
||||
* @param app The main application instance.
|
||||
*/
|
||||
public ImpactEffectManager(Application app) {
|
||||
public ImpactEffectManager(BattleshipApp app) {
|
||||
this.app = app;
|
||||
this.assetManager = app.getAssetManager();
|
||||
this.particleMaterial = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
|
||||
}
|
||||
@@ -41,14 +44,16 @@ public ImpactEffectManager(Application app) {
|
||||
* @param shot The details of the shot where the hit occurred.
|
||||
*/
|
||||
public void triggerHitEffect(Node battleshipNode, Shot shot) {
|
||||
ParticleEmitter hitEffect = createParticleEmitter("HitEffect", 30, ColorRGBA.Orange, ColorRGBA.Red, 0.45f, 0.1f, 1f, 2f);
|
||||
ParticleEmitter hitEffect = createParticleEmitter("HitEffect", 50, ColorRGBA.Orange, ColorRGBA.Red, 0.45f, 0.1f, 1f, 2f);
|
||||
|
||||
hitEffect.setLocalTranslation(shot.getY() + 0.5f, 0, shot.getX() + 0.5f);
|
||||
|
||||
LOGGER.log(Level.DEBUG, "Hit effect created at position: {0}", hitEffect.getLocalTranslation().toString());
|
||||
|
||||
hitEffect.emitAllParticles();
|
||||
battleshipNode.attachChild(hitEffect);
|
||||
hitEffect.addControl(new EffectCleanupControl(hitEffect, battleshipNode));
|
||||
// hitEffect.emitAllParticles();
|
||||
hitEffect.addControl(new EffectCleanupControl(hitEffect));
|
||||
|
||||
app.getRootNode().attachChild(hitEffect);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,9 +63,8 @@ public void triggerHitEffect(Node battleshipNode, Shot shot) {
|
||||
* @return The particle emitter representing the miss effect.
|
||||
*/
|
||||
public ParticleEmitter triggerMissEffect(Shot shot) {
|
||||
ParticleEmitter missEffect = createParticleEmitter("MissEffect", 15, ColorRGBA.Blue, ColorRGBA.Cyan, 0.3f, 0.05f, 0.5f, 1.5f);
|
||||
ParticleEmitter missEffect = createParticleEmitter("MissEffect", 50, ColorRGBA.Blue, ColorRGBA.Cyan, 0.3f, 0.05f, 0.5f, 1.5f);
|
||||
missEffect.setLocalTranslation(shot.getY() + 0.5f, 0, shot.getX() + 0.5f);
|
||||
missEffect.emitAllParticles();
|
||||
missEffect.addControl(new EffectCleanupControl(missEffect));
|
||||
return missEffect;
|
||||
}
|
||||
@@ -80,6 +84,7 @@ public ParticleEmitter triggerMissEffect(Shot shot) {
|
||||
*/
|
||||
private ParticleEmitter createParticleEmitter(String name, int count, ColorRGBA startColor, ColorRGBA endColor, float startSize, float endSize, float lowLife, float highLife) {
|
||||
ParticleEmitter emitter = new ParticleEmitter(name, Type.Triangle, count);
|
||||
emitter.setNumParticles(0);
|
||||
emitter.setMaterial(particleMaterial);
|
||||
emitter.setImagesX(2);
|
||||
emitter.setImagesY(2);
|
||||
@@ -91,7 +96,6 @@ private ParticleEmitter createParticleEmitter(String name, int count, ColorRGBA
|
||||
emitter.setGravity(0, -0.5f, 0);
|
||||
emitter.setLowLife(lowLife);
|
||||
emitter.setHighLife(highLife);
|
||||
emitter.setParticlesPerSec(0);
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@@ -101,7 +105,10 @@ private ParticleEmitter createParticleEmitter(String name, int count, ColorRGBA
|
||||
private static class EffectCleanupControl extends AbstractControl {
|
||||
|
||||
private final ParticleEmitter emitter;
|
||||
private final Node attachedNode;
|
||||
// private final Node attachedNode;
|
||||
|
||||
private float currentTime = 0;
|
||||
private final float duration = 3.5f;
|
||||
|
||||
/**
|
||||
* Constructor for managing cleanup when a particle emitter is attached to a specific node.
|
||||
@@ -109,10 +116,10 @@ private static class EffectCleanupControl extends AbstractControl {
|
||||
* @param emitter The particle emitter to manage.
|
||||
* @param attachedNode The node to which the emitter is attached.
|
||||
*/
|
||||
public EffectCleanupControl(ParticleEmitter emitter, Node attachedNode) {
|
||||
this.emitter = emitter;
|
||||
this.attachedNode = attachedNode;
|
||||
}
|
||||
// public EffectCleanupControl(ParticleEmitter emitter, Node attachedNode) {
|
||||
// this.emitter = emitter;
|
||||
// this.attachedNode = attachedNode;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Constructor for managing cleanup of a standalone particle emitter.
|
||||
@@ -120,7 +127,8 @@ public EffectCleanupControl(ParticleEmitter emitter, Node attachedNode) {
|
||||
* @param emitter The particle emitter to manage.
|
||||
*/
|
||||
public EffectCleanupControl(ParticleEmitter emitter) {
|
||||
this(emitter, null);
|
||||
// this(emitter, null);
|
||||
this.emitter = emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,10 +138,23 @@ public EffectCleanupControl(ParticleEmitter emitter) {
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (emitter.getParticlesPerSec() == 0 && emitter.getNumVisibleParticles() == 0) {
|
||||
if (attachedNode != null) {
|
||||
attachedNode.detachChild(emitter);
|
||||
}
|
||||
currentTime += tpf;
|
||||
if (currentTime <= duration) {
|
||||
|
||||
}
|
||||
if (currentTime >= 1f && currentTime <= 1.1) {
|
||||
|
||||
//Start
|
||||
emitter.setNumParticles(50);
|
||||
emitter.setParticlesPerSec(50);
|
||||
}
|
||||
if (currentTime >= duration){
|
||||
emitter.setParticlesPerSec(0);
|
||||
}
|
||||
if (currentTime >= duration+1f) {
|
||||
//Ende
|
||||
spatial.removeFromParent();
|
||||
emitter.emitAllParticles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
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;
|
||||
|
||||
@@ -109,6 +110,11 @@ public Spatial visit(Battleship ship) {
|
||||
return shipNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spatial visit(Shell shell) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a line geometry representing part of the ship's border.
|
||||
*
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.scene.shape.Cylinder;
|
||||
import pp.battleship.client.BattleshipApp;
|
||||
import pp.battleship.model.Battleship;
|
||||
import pp.battleship.model.Rotation;
|
||||
import pp.battleship.model.ShipMap;
|
||||
import pp.battleship.model.Shot;
|
||||
import pp.battleship.model.*;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static pp.util.FloatMath.HALF_PI;
|
||||
@@ -35,9 +32,10 @@
|
||||
class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
|
||||
private static final String KING_GEORGE_V_MODEL = "Models/KingGeorgeV/KingGeorgeV.j3o";//NON-NLS
|
||||
private static final String DESTROYER = "Models/Destroyer/10619_Battleship.obj";
|
||||
private static final String DESTROYER = "Models/Destroyer/Destroyer.j3o";
|
||||
private static final String FERRY = "Models/Ferry/13922_Staten_Island_Ferry_V1_l1.obj";
|
||||
private static final String SMALL = "Models/Small/10634_SpeedBoat_v01_LOD3.obj";
|
||||
private static final String BOMB = "Models/Bomb/BombGBU.j3o";
|
||||
private static final String COLOR = "Color"; //NON-NLS
|
||||
private static final String SHIP = "ship"; //NON-NLS
|
||||
private static final String SHOT = "shot"; //NON-NLS
|
||||
@@ -89,6 +87,7 @@ private Spatial handleHit(Shot shot) {
|
||||
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
|
||||
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
|
||||
|
||||
System.out.println(shot.getX() + " " + shot.getY());
|
||||
effectHandler.triggerHitEffect(shipNode, shot);
|
||||
|
||||
return null;
|
||||
@@ -136,6 +135,23 @@ public Spatial visit(Battleship ship) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spatial visit(Shell shell) {
|
||||
final Spatial bombModel = app.getAssetManager().loadModel(BOMB);
|
||||
|
||||
// Apply transformations to the bomb model (scale, rotate, etc. if needed)
|
||||
bombModel.scale(0.05f); // Adjust the scale based on your model size
|
||||
bombModel.rotate(-HALF_PI, 0f, 0f); // Rotate the model if necessary
|
||||
|
||||
// Set the position of the bomb at the shell's current position
|
||||
bombModel.setLocalTranslation(shell.getCurrentPosition());
|
||||
|
||||
// Add a control to animate the bomb's movement (similar to the previous cylinder animation)
|
||||
bombModel.addControl(new ShellControl(shell));
|
||||
|
||||
return bombModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the appropriate graphical representation of the specified battleship.
|
||||
* The representation is a detailed model based on the length of the ship.
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
////////////////////////////////////////
|
||||
// Programming project code
|
||||
// UniBw M, 2022, 2023, 2024
|
||||
// www.unibw.de/inf2
|
||||
// (c) Mark Minas (mark.minas@unibw.de)
|
||||
////////////////////////////////////////
|
||||
|
||||
package pp.battleship.client.gui;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.battleship.model.Battleship;
|
||||
import pp.battleship.model.Shell;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
|
||||
|
||||
import static pp.util.FloatMath.DEG_TO_RAD;
|
||||
import static pp.util.FloatMath.TWO_PI;
|
||||
import static pp.util.FloatMath.sin;
|
||||
|
||||
/**
|
||||
* Controls the oscillating pitch motion of a battleship model in the game.
|
||||
* The ship oscillates to simulate a realistic movement on water, based on its orientation and length.
|
||||
*/
|
||||
class ShellControl extends AbstractControl {
|
||||
/**
|
||||
* The axis of rotation for the ship's pitch (tilting forward and backward).
|
||||
*/
|
||||
private final Vector3f axis;
|
||||
|
||||
/**
|
||||
* The duration of one complete oscillation cycle in seconds.
|
||||
*/
|
||||
private final float cycle;
|
||||
|
||||
/**
|
||||
* The amplitude of the pitch oscillation in radians, determining how much the ship tilts.
|
||||
*/
|
||||
private final float amplitude;
|
||||
|
||||
/**
|
||||
* A quaternion representing the ship's current pitch rotation.
|
||||
*/
|
||||
private final Quaternion pitch = new Quaternion();
|
||||
|
||||
/**
|
||||
* The current time within the oscillation cycle, used to calculate the ship's pitch angle.
|
||||
*/
|
||||
private float time;
|
||||
|
||||
private Shell shell;
|
||||
/**
|
||||
* Logger for logging messages related to ShipControl operations.
|
||||
*/
|
||||
static final Logger LOGGER = System.getLogger(ShipControl.class.getName());
|
||||
|
||||
/**
|
||||
* Constructs a new ShipControl instance for the specified Battleship.
|
||||
* The ship's orientation determines the axis of rotation, while its length influences
|
||||
* the cycle duration and amplitude of the oscillation.
|
||||
*
|
||||
* @param shell the Battleship object to control
|
||||
*/
|
||||
public ShellControl(Shell shell) {
|
||||
this.shell = shell;
|
||||
// Determine the axis of rotation based on the ship's orientation
|
||||
axis = Vector3f.UNIT_X;
|
||||
|
||||
// Set the cycle duration and amplitude based on the ship's length
|
||||
cycle = 1 * 2f;
|
||||
amplitude = 5f * DEG_TO_RAD / 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ship's pitch oscillation each frame. The ship's pitch is adjusted
|
||||
* to create a continuous tilting motion, simulating the effect of waves.
|
||||
*
|
||||
* @param tpf time per frame (in seconds), used to calculate the new pitch angle
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
// If spatial is null, do nothing
|
||||
if (spatial == null) return;
|
||||
|
||||
shell.updatePosition(tpf);
|
||||
spatial.setLocalTranslation(shell.getCurrentPosition());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
# Blender MTL File: 'untitletttd.blend'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl None
|
||||
Ns 0
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.8 0.8 0.8
|
||||
d 1
|
||||
illum 2
|
||||
map_Kd C:\Users\Convidado.Cliente-JMF-PC\Desktop\ghftht.png
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
based on:
|
||||
https://free3d.com/3d-model/battleship-v1--611736.html
|
||||
License: Free Personal Use Only
|
||||
@@ -0,0 +1,3 @@
|
||||
based on:
|
||||
https://free3d.com/3d-model/statenislandferry-v1--603882.html
|
||||
License: Free Personal Use Only
|
||||
@@ -0,0 +1,3 @@
|
||||
based on:
|
||||
https://free3d.com/3d-model/speedboat-v01--840133.html
|
||||
License: Free Personal Use Only
|
||||
@@ -41,7 +41,7 @@ public static void main(String[] args) {
|
||||
*/
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS
|
||||
export("Models/Destroyer/10619_Battleship.obj", "Destroyer.j3o"); //NON-NLS
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
# Blender MTL File: 'untitletttd.blend'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl None
|
||||
Ns 0
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.8 0.8 0.8
|
||||
d 1
|
||||
illum 2
|
||||
map_Kd C:\Users\Convidado.Cliente-JMF-PC\Desktop\ghftht.png
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
based on:
|
||||
https://free3d.com/3d-model/battleship-v1--611736.html
|
||||
License: Free Personal Use Only
|
||||
@@ -7,9 +7,11 @@
|
||||
|
||||
package pp.battleship.game.client;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import pp.battleship.message.client.ShootMessage;
|
||||
import pp.battleship.message.server.EffectMessage;
|
||||
import pp.battleship.model.IntPoint;
|
||||
import pp.battleship.model.Shell;
|
||||
import pp.battleship.model.ShipMap;
|
||||
import pp.battleship.notification.Sound;
|
||||
|
||||
@@ -57,6 +59,7 @@ public void receivedEffect(EffectMessage msg) {
|
||||
myTurn = msg.isMyTurn();
|
||||
logic.setInfoText(msg.getInfoTextKey());
|
||||
affectedMap(msg).add(msg.getShot());
|
||||
affectedMap(msg).add(new Shell(new Vector3f(0, 10, 0), new Vector3f(msg.getShot().getY() + 0.5f, -0.4f, msg.getShot().getX() + 0.5f), 1f));
|
||||
if (destroyedOpponentShip(msg))
|
||||
logic.getOpponentMap().add(msg.getDestroyedShip());
|
||||
if (msg.isGameOver()) {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package pp.battleship.model;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import pp.util.FloatMath;
|
||||
|
||||
public class Shell implements Item {
|
||||
private Vector3f startPosition; // Startposition des Geschosses
|
||||
private Vector3f targetPosition; // Zielposition des Geschosses0
|
||||
private Vector3f currentPosition; // Aktuelle Position des Geschosses
|
||||
private float speed; // Geschwindigkeit des Geschosses
|
||||
|
||||
private float progress;
|
||||
|
||||
public Shell(Vector3f startPosition, Vector3f targetPosition, float speed) {
|
||||
this.startPosition = startPosition;
|
||||
this.targetPosition = targetPosition;
|
||||
this.currentPosition = new Vector3f(startPosition); // Initiale Position ist die Startposition
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
// Methode, um die Position des Geschosses basierend auf der Zeit zu aktualisieren
|
||||
public void updatePosition(float deltaTime) {
|
||||
progress+=deltaTime*speed;
|
||||
|
||||
// Interpoliere die Position zwischen Start- und Zielposition basierend auf dem Fortschritt
|
||||
currentPosition.x = FloatMath.interpolateLinear(progress,startPosition.x,targetPosition.x);
|
||||
currentPosition.y = FloatMath.interpolateLinear(progress,startPosition.y,targetPosition.y);
|
||||
currentPosition.z = FloatMath.interpolateLinear(progress,startPosition.z,targetPosition.z);
|
||||
|
||||
//currentPosition.interpolateLocal(startPosition, targetPosition, progress);
|
||||
}
|
||||
|
||||
// Aktuelle Position des Geschosses
|
||||
public Vector3f getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
// Überprüfen, ob das Ziel erreicht ist
|
||||
public boolean isAtTarget() {
|
||||
return currentPosition.distance(targetPosition) < 0.0001f; // Toleranz für die Zielgenauigkeit
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(Visitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a visitor that does not return a value. This method is part of the
|
||||
* Visitor design pattern.
|
||||
*
|
||||
* @param visitor the visitor to accept
|
||||
*/
|
||||
@Override
|
||||
public void accept(VoidVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,14 @@ public void add(Battleship ship) {
|
||||
addItem(ship);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param shell
|
||||
*/
|
||||
public void add(Shell shell){
|
||||
addItem(shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a shot on the map, updates the state of the affected ship (if any),
|
||||
* and triggers an item addition event.
|
||||
|
||||
@@ -28,4 +28,6 @@ public interface Visitor<T> {
|
||||
* @return the result of visiting the Battleship element
|
||||
*/
|
||||
T visit(Battleship ship);
|
||||
|
||||
T visit(Shell shell);
|
||||
}
|
||||
|
||||
@@ -25,4 +25,6 @@ public interface VoidVisitor {
|
||||
* @param ship the Battleship element to visit
|
||||
*/
|
||||
void visit(Battleship ship);
|
||||
|
||||
void visit(Shell shell);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user