mirror of
https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
synced 2025-08-01 07:13:48 +02:00
Compare commits
4 Commits
96a78ee61b
...
b_malkmus_
Author | SHA1 | Date | |
---|---|---|---|
|
a0dffbfc34 | ||
|
7076e204af | ||
|
50559f5785 | ||
|
f5dc8a0f05 |
@@ -9,6 +9,8 @@ dependencies {
|
||||
implementation project(":battleship:model")
|
||||
|
||||
implementation libs.jme3.desktop
|
||||
implementation 'com.simsilica:lemur:1.14.0'
|
||||
implementation 'com.simsilica:lemur-proto:1.10.0'
|
||||
|
||||
runtimeOnly libs.jme3.awt.dialogs
|
||||
runtimeOnly libs.jme3.plugins
|
||||
|
@@ -0,0 +1,127 @@
|
||||
package pp.battleship.client;
|
||||
|
||||
import com.jme3.app.Application;
|
||||
import com.jme3.app.state.AbstractAppState;
|
||||
import com.jme3.app.state.AppStateManager;
|
||||
import com.jme3.asset.AssetLoadException;
|
||||
import com.jme3.asset.AssetNotFoundException;
|
||||
import com.jme3.audio.AudioData;
|
||||
import com.jme3.audio.AudioNode;
|
||||
import pp.battleship.notification.GameEventListener;
|
||||
import pp.battleship.notification.SoundEvent;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static pp.util.PreferencesUtils.getPreferences;
|
||||
|
||||
/**
|
||||
* An application state that plays music.
|
||||
*/
|
||||
public class GameMusic extends AbstractAppState {
|
||||
private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
|
||||
private static final Preferences PREFERENCES = getPreferences(GameMusic.class);
|
||||
private static final String ENABLED_PREF = "enabled"; //NON-NLS
|
||||
private static final String VOLUME_PREF = "volume"; //NON-NLS
|
||||
|
||||
private AudioNode piratenMusic;
|
||||
|
||||
|
||||
/**
|
||||
* Checks if sound is enabled in the preferences.
|
||||
*
|
||||
* @return {@code true} if sound is enabled, {@code false} otherwise.
|
||||
*/
|
||||
|
||||
//Prüft, ob die Musik eingeschalten ist.
|
||||
public static boolean enabledInPreferences() {
|
||||
return PREFERENCES.getBoolean(ENABLED_PREF, true);
|
||||
}
|
||||
/**
|
||||
* Checks enabled volume in preferences.
|
||||
*
|
||||
* @return {@code float} if a volumePreference is set, the volume is set to the Value in PREFERENCES,
|
||||
* {@code 0.25f} if no volumePreference is set in PREFERENCES, the Volume is set to a default of 0.25f
|
||||
*
|
||||
*/
|
||||
|
||||
//Standardeinstellung für Musik
|
||||
public static float volumePreference() {
|
||||
return PREFERENCES.getFloat(VOLUME_PREF, 0.33f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the game sound on or off.
|
||||
*/
|
||||
public void toggleSound() {
|
||||
setEnabled(!isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled state of this AppState.
|
||||
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
|
||||
*
|
||||
* @param enabled {@code true} to enable the AppState, {@code false} to disable it.
|
||||
*/
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (isEnabled() == enabled) return;
|
||||
else if (!isEnabled() && enabled) {
|
||||
if (piratenMusic != null) piratenMusic.play();
|
||||
} else if (isEnabled() && !enabled) {
|
||||
if (piratenMusic != null) piratenMusic.stop();
|
||||
}
|
||||
|
||||
super.setEnabled(enabled);
|
||||
LOGGER.log(Level.INFO, "Music enabled: {0}", enabled); //NON-NLS
|
||||
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the music.
|
||||
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
|
||||
*
|
||||
* @param stateManager The state manager
|
||||
* @param app The application
|
||||
*/
|
||||
@Override
|
||||
public void initialize(AppStateManager stateManager, Application app) {
|
||||
super.initialize(stateManager, app);
|
||||
piratenMusic =loadSound(app, "Sound/BackgroundMusic/Piratenmusik.ogg");
|
||||
setVolume(volumePreference());
|
||||
piratenMusic.setLooping(true);
|
||||
if (isEnabled() && piratenMusic != null) {
|
||||
piratenMusic.play();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the music from the specified file.
|
||||
*
|
||||
* @param app The application
|
||||
* @param name The name of the sound file.
|
||||
* @return The loaded AudioNode.
|
||||
*/
|
||||
private AudioNode loadSound(Application app, String name) {
|
||||
try {
|
||||
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
||||
sound.setLooping(false);
|
||||
sound.setPositional(false);
|
||||
return sound;
|
||||
}
|
||||
catch (AssetLoadException | AssetNotFoundException ex) {
|
||||
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Einstellung der Lautstärke
|
||||
public void setVolume(float vol){
|
||||
piratenMusic.setVolume(vol);
|
||||
PREFERENCES.putFloat(VOLUME_PREF, vol);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,10 +7,14 @@
|
||||
|
||||
package pp.battleship.client;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.simsilica.lemur.Button;
|
||||
import com.simsilica.lemur.Checkbox;
|
||||
import com.simsilica.lemur.Label;
|
||||
import com.simsilica.lemur.RangedValueModel;
|
||||
import com.simsilica.lemur.style.ElementId;
|
||||
import com.simsilica.lemur.Slider;
|
||||
import pp.battleship.client.gui.VolumeSlider;
|
||||
import pp.dialog.Dialog;
|
||||
import pp.dialog.StateCheckboxModel;
|
||||
import pp.dialog.TextInputDialog;
|
||||
@@ -33,6 +37,7 @@ class Menu extends Dialog {
|
||||
private final BattleshipApp app;
|
||||
private final Button loadButton = new Button(lookup("menu.map.load"));
|
||||
private final Button saveButton = new Button(lookup("menu.map.save"));
|
||||
private final VolumeSlider volumeSlider;
|
||||
|
||||
/**
|
||||
* Constructs the Menu dialog for the Battleship application.
|
||||
@@ -45,6 +50,26 @@ class Menu extends Dialog {
|
||||
addChild(new Label(lookup("battleship.name"), new ElementId("header"))); //NON-NLS
|
||||
addChild(new Checkbox(lookup("menu.sound-enabled"),
|
||||
new StateCheckboxModel(app, GameSound.class)));
|
||||
addChild(new Label(lookup("battleship.name"), new ElementId("header")));//NON-NLS
|
||||
|
||||
addChild(new Checkbox(lookup("menu.sound-enabled"), new StateCheckboxModel(app, GameSound.class)));
|
||||
|
||||
addChild(new Checkbox(lookup("menu.background-sound-enabled"), new StateCheckboxModel(app, GameMusic.class)));
|
||||
|
||||
volumeSlider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
|
||||
|
||||
addChild(volumeSlider);
|
||||
|
||||
addChild(loadButton)
|
||||
.addClickCommands(s -> ifTopDialog(this::loadDialog));
|
||||
addChild(saveButton);
|
||||
saveButton.setEnabled(app.getGameLogic().maySaveMap());
|
||||
|
||||
|
||||
|
||||
// Füge den Slider zum GUI hinzu
|
||||
addChild(volumeSlider);
|
||||
|
||||
addChild(loadButton)
|
||||
.addClickCommands(s -> ifTopDialog(this::loadDialog));
|
||||
addChild(saveButton)
|
||||
@@ -140,4 +165,6 @@ class Menu extends Dialog {
|
||||
private void saveDialog() {
|
||||
fileDialog(app.getGameLogic()::saveMap, lookup("menu.map.save"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ import com.simsilica.lemur.Container;
|
||||
import com.simsilica.lemur.Label;
|
||||
import com.simsilica.lemur.TextField;
|
||||
import com.simsilica.lemur.component.SpringGridLayout;
|
||||
import com.simsilica.lemur.Button;
|
||||
import pp.battleship.server.BattleshipServer;
|
||||
import pp.dialog.Dialog;
|
||||
import pp.dialog.DialogBuilder;
|
||||
import pp.dialog.SimpleDialog;
|
||||
@@ -33,6 +35,8 @@ class NetworkDialog extends SimpleDialog {
|
||||
private final NetworkSupport network;
|
||||
private final TextField host = new TextField(LOCALHOST);
|
||||
private final TextField port = new TextField(DEFAULT_PORT);
|
||||
// private final Button serverButton = new Button(lookup("client.server-star"));
|
||||
private final Button serverButton = new Button(lookup("client.server-start"));
|
||||
private String hostname;
|
||||
private int portNumber;
|
||||
private Future<Object> connectionFuture;
|
||||
@@ -65,6 +69,10 @@ class NetworkDialog extends SimpleDialog {
|
||||
.setOkClose(false)
|
||||
.setNoClose(false)
|
||||
.build(this);
|
||||
|
||||
//Add the button to start the sever
|
||||
addChild(serverButton).addClickCommands(s -> ifTopDialog(this::startServerInThread));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,4 +158,21 @@ class NetworkDialog extends SimpleDialog {
|
||||
network.getApp().errorDialog(lookup("server.connection.failed"));
|
||||
network.getApp().setInfoText(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server in a separate thread.
|
||||
*/
|
||||
private void startServerInThread() {
|
||||
serverButton.setEnabled(false);
|
||||
Thread serverThread = new Thread(() -> {
|
||||
try {
|
||||
BattleshipServer.main(null);
|
||||
} catch (Exception e) {
|
||||
serverButton.setEnabled(true);
|
||||
LOGGER.log(Level.ERROR, "Server could not be started", e);
|
||||
network.getApp().errorDialog("Could not start server: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
serverThread.start();
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -32,9 +32,13 @@ import static pp.util.FloatMath.PI;
|
||||
* It extends the {@link ShipMapSynchronizer} to provide specific synchronization
|
||||
* logic for the sea map.
|
||||
*/
|
||||
//ANPASSEN!!!!
|
||||
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 FLUGZEUGTRAEGER = "Models/Flugzeugträger_5er/Flugzeugträger.j3o";
|
||||
private static final String KORVETTE = "Models/Korvette_3er/Korvette.j3o";
|
||||
private static final String ZERSTOERER = "Models/Zerstörer_2er/Zerstörer.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
|
||||
@@ -44,6 +48,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
|
||||
private final ShipMap map;
|
||||
private final BattleshipApp app;
|
||||
private final ParticleEffectFactory particleFactory;
|
||||
|
||||
/**
|
||||
* Constructs a {@code SeaSynchronizer} object with the specified application, root node, and ship map.
|
||||
@@ -56,6 +61,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
super(app.getGameLogic().getOwnMap(), root);
|
||||
this.app = app;
|
||||
this.map = map;
|
||||
this.particleFactory = new ParticleEffectFactory(app);
|
||||
addExisting();
|
||||
}
|
||||
|
||||
@@ -80,17 +86,95 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
* @return always null to prevent the representation from being attached
|
||||
* to the items node as well
|
||||
*/
|
||||
private Spatial handleMiss(Shot shot) {
|
||||
Node shotNode = new Node("ShotNode");
|
||||
Geometry shotCylinder = createCylinder(shot);
|
||||
shotNode.attachChild(shotCylinder);
|
||||
ParticleEmitter waterSplash = particleFactory.createWaterSplash();
|
||||
waterSplash.setLocalTranslation(shot.getY() + 0.5f, 0f, shot.getX() + 0.5f);
|
||||
shotNode.attachChild(waterSplash);
|
||||
waterSplash.emitAllParticles();
|
||||
|
||||
return shotNode;
|
||||
}
|
||||
|
||||
* @param shot a hit
|
||||
* @return always null to prevent the representation from being attached to the items node as well
|
||||
*/
|
||||
private Spatial handleHit(Shot shot) {
|
||||
final Battleship ship = requireNonNull(map.findShipAt(shot), "Missing ship");
|
||||
final Node shipNode = requireNonNull((Node) getSpatial(ship), "Missing ship node");
|
||||
|
||||
final Geometry representation = createCylinder(shot);
|
||||
representation.getLocalTranslation().subtractLocal(shipNode.getLocalTranslation());
|
||||
shipNode.attachChild(representation);
|
||||
|
||||
|
||||
// Create a new node specifically for the hit effects
|
||||
Node hitEffectNode = new Node("HitEffectNode");
|
||||
|
||||
// Create particle effects
|
||||
ParticleEmitter flame = particleFactory.createFlame();
|
||||
ParticleEmitter flash = particleFactory.createFlash();
|
||||
ParticleEmitter spark = particleFactory.createSpark();
|
||||
ParticleEmitter roundSpark = particleFactory.createRoundSpark();
|
||||
ParticleEmitter smokeTrail = particleFactory.createSmokeTrail();
|
||||
ParticleEmitter debris = particleFactory.createDebris();
|
||||
ParticleEmitter shockwave = particleFactory.createShockwave();
|
||||
ParticleEmitter movingSmoke = particleFactory.createMovingSmokeEmitter();
|
||||
|
||||
// Attach all effects to the hitEffectNode
|
||||
hitEffectNode.attachChild(flame);
|
||||
hitEffectNode.attachChild(flash);
|
||||
hitEffectNode.attachChild(spark);
|
||||
hitEffectNode.attachChild(roundSpark);
|
||||
hitEffectNode.attachChild(smokeTrail);
|
||||
hitEffectNode.attachChild(debris);
|
||||
hitEffectNode.attachChild(shockwave);
|
||||
hitEffectNode.attachChild(movingSmoke);
|
||||
|
||||
// Set the local translation for the hit effect to the point of impact
|
||||
hitEffectNode.setLocalTranslation(shot.getY() + 0.5f - shipNode.getLocalTranslation().x,
|
||||
0.5f, // Adjust as needed for height above the ship
|
||||
shot.getX() + 0.5f - shipNode.getLocalTranslation().z);
|
||||
|
||||
// Attach the hitEffectNode to the shipNode so it moves with the ship
|
||||
shipNode.attachChild(hitEffectNode);
|
||||
|
||||
// Emit particles when the hit happens
|
||||
flash.emitAllParticles();
|
||||
spark.emitAllParticles();
|
||||
smokeTrail.emitAllParticles();
|
||||
debris.emitAllParticles();
|
||||
shockwave.emitAllParticles();
|
||||
flame.emitAllParticles();
|
||||
roundSpark.emitAllParticles();
|
||||
|
||||
//Checks if ship is destroyed and triggers animation accordingly
|
||||
if (ship.isDestroyed()) {
|
||||
sinkAndRemoveShip(ship);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the sinking animation and removal of ship if destroyed
|
||||
* @param ship the ship to be sunk
|
||||
*/
|
||||
private void sinkAndRemoveShip(Battleship ship) {
|
||||
|
||||
final Node shipNode = (Node) getSpatial(ship);
|
||||
if (shipNode == null) return;
|
||||
|
||||
// Add sinking control to animate the sinking
|
||||
shipNode.addControl(new SinkingControl(shipNode));
|
||||
|
||||
// Add particle effects
|
||||
ParticleEmitter bubbles = particleFactory.createWaterSplash();
|
||||
bubbles.setLocalTranslation(shipNode.getLocalTranslation());
|
||||
shipNode.attachChild(bubbles);
|
||||
bubbles.emitAllParticles();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a cylinder geometry representing the specified shot.
|
||||
* The appearance of the cylinder depends on whether the shot is a hit or a miss.
|
||||
@@ -140,8 +224,14 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
* @param ship the battleship to be represented
|
||||
* @return the spatial representing the battleship
|
||||
*/
|
||||
//ANPASSEN!!!!!!
|
||||
private Spatial createShip(Battleship ship) {
|
||||
return ship.getLength() == 4 ? createBattleship(ship) : createBox(ship);
|
||||
if( ship.getLength() == 4){ createBox(ship); return createBattleship(ship); }
|
||||
else if(ship.getLength()==5){createBox(ship);return createFlugzeugtraeger(ship); }
|
||||
else if(ship.getLength()==3){createBox(ship);return createKorvette(ship); }
|
||||
else if(ship.getLength()==2){createBox(ship);return createZerstoerer(ship); }
|
||||
else if(ship.getLength()==1){createBox(ship);return createZerstoerer(ship); }
|
||||
else throw new IllegalArgumentException("Deine Länge ist nicht definiert!");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,6 +276,7 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
* @param ship the battleship to be represented
|
||||
* @return the spatial representing the "King George V" battleship
|
||||
*/
|
||||
//ANPASSEN!!!!
|
||||
private Spatial createBattleship(Battleship ship) {
|
||||
final Spatial model = app.getAssetManager().loadModel(KING_GEORGE_V_MODEL);
|
||||
|
||||
@@ -196,6 +287,36 @@ class SeaSynchronizer extends ShipMapSynchronizer {
|
||||
return model;
|
||||
}
|
||||
|
||||
private Spatial createFlugzeugtraeger(Battleship ship) {
|
||||
final Spatial model = app.getAssetManager().loadModel(FLUGZEUGTRAEGER);
|
||||
|
||||
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
|
||||
model.scale(1.48f);
|
||||
model.setShadowMode(ShadowMode.CastAndReceive);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private Spatial createKorvette(Battleship ship) {
|
||||
final Spatial model = app.getAssetManager().loadModel(KORVETTE);
|
||||
|
||||
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
|
||||
model.scale(1.48f);
|
||||
model.setShadowMode(ShadowMode.CastAndReceive);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private Spatial createZerstoerer(Battleship ship) {
|
||||
final Spatial model = app.getAssetManager().loadModel(ZERSTOERER);
|
||||
|
||||
model.rotate(-HALF_PI, calculateRotationAngle(ship.getRot()), 0f);
|
||||
model.scale(1.48f);
|
||||
model.setShadowMode(ShadowMode.CastAndReceive);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the rotation angle for the specified rotation.
|
||||
*
|
||||
|
@@ -0,0 +1,53 @@
|
||||
package pp.battleship.client.gui;
|
||||
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.Node;
|
||||
|
||||
/**
|
||||
* Control that handles the sinking effect for destroyed ships.
|
||||
* It will gradually move the ship downwards and then remove it from the scene.
|
||||
*/
|
||||
class SinkingControl extends AbstractControl {
|
||||
private static final float SINK_DURATION = 5f; // Duration of the sinking animation
|
||||
private static final float SINK_SPEED = 0.1f; // Speed at which the ship sinks
|
||||
private float elapsedTime = 0;
|
||||
|
||||
private final Node shipNode;
|
||||
|
||||
/**
|
||||
* Constructs a {@code SinkingControl.java} object with the shipNode to be to be sunk
|
||||
* @param shipNode the node to handeld
|
||||
*/
|
||||
public SinkingControl(Node shipNode) {
|
||||
this.shipNode = shipNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated the Map to sink the ship
|
||||
*
|
||||
* @param tpf time per frame
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
// Update the sinking effect
|
||||
elapsedTime += tpf;
|
||||
|
||||
// Move the ship down over time
|
||||
Vector3f currentPos = shipNode.getLocalTranslation();
|
||||
shipNode.setLocalTranslation(currentPos.x, currentPos.y - SINK_SPEED * tpf, currentPos.z);
|
||||
|
||||
// Check if sinking duration has passed
|
||||
if (elapsedTime >= SINK_DURATION) {
|
||||
// Remove the ship from the scene
|
||||
shipNode.removeFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
// No rendering-related code needed
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package pp.battleship.client.gui;
|
||||
|
||||
import com.simsilica.lemur.Slider;
|
||||
import pp.battleship.client.GameMusic;
|
||||
|
||||
|
||||
public class VolumeSlider extends Slider {
|
||||
|
||||
private final GameMusic piratenMusic;
|
||||
|
||||
private double vol;
|
||||
|
||||
public VolumeSlider(GameMusic music) {
|
||||
super();
|
||||
this.piratenMusic = music;
|
||||
vol = GameMusic.volumePreference();
|
||||
getModel().setPercent(vol);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (vol != getModel().getPercent()) {
|
||||
vol = getModel().getPercent();
|
||||
piratenMusic.setVolume( (float) vol);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@@ -42,10 +42,13 @@ public class ModelExporter extends SimpleApplication {
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
export("Models/KingGeorgeV/King_George_V.obj", "KingGeorgeV.j3o"); //NON-NLS
|
||||
|
||||
export("Models/Flugzeugträger_5er/Flugzeugträger.obj", "Flugzeugträger.j3o");
|
||||
export("Models/Korvette_3er/caravel.obj", "Korvette.j3o");
|
||||
export("Models/Zerstörer_2er/ShipV_LOW.obj", "Zerstörer.j3o");
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports spatial into a file
|
||||
*
|
||||
|
@@ -0,0 +1,112 @@
|
||||
# Blender 4.2.2 LTS MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Main.002
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.490000 0.257495 0.132300
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.016
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.000000 0.000000 0.000000
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.017
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.190000 0.077615 0.017100
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.018
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.266600 0.466860 0.620000
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.019
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.990000 0.990000 0.990000
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.020
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.070000 0.062265 0.058100
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.021
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.160000 0.151680 0.147200
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.022
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.340000 0.164333 0.000000
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.023
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.940000 0.561180 0.206800
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Mat.1_1.002
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.320000 0.151520 0.060800
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl Sail.002
|
||||
Ns 319.999939
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.070000 0.070000 0.070000
|
||||
Ks 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 2
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
# Blender 4.2.2 LTS MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl DeckStuff.003
|
||||
Ns 20.000006
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.184314 0.600000 0.792157
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl Hull.003
|
||||
Ns 20.000006
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.701961 0.678431 0.019608
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl MastsRigging.003
|
||||
Ns 20.000006
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.086275 0.768628 0.117647
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl Poopdeck.003
|
||||
Ns 20.000006
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.976471 0.211765 0.211765
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl Sail.007
|
||||
Ns 20.000006
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.588000 0.588000 0.588000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 1
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
# Blender 4.2.2 LTS MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl map_ShipV_001
|
||||
Ns 224.999985
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.800000 0.144874 0.000708
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl map_ShipV_002
|
||||
Ns 224.999985
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.800000 0.035888 0.004678
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl map_ShipV_003
|
||||
Ns 224.999985
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.001405 0.006690 0.800000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -72,7 +72,7 @@ class BattleState extends ClientState {
|
||||
* @return the map (either the opponent's or player's own map) that is affected by the shot
|
||||
*/
|
||||
private ShipMap affectedMap(EffectMessage msg) {
|
||||
return msg.isOwnShot() ? logic.getOpponentMap() : logic.getOwnMap();
|
||||
return msg.isOwnShot() ? logic.getOpponentMap() : logic.getOpponentMap();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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.");
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
package pp.battleship.game.server;
|
||||
|
||||
import pp.battleship.BattleshipConfig;
|
||||
import pp.battleship.model.Battleship;
|
||||
import pp.battleship.model.ShipMap;
|
||||
|
||||
/**
|
||||
@@ -51,4 +52,9 @@ public class Player {
|
||||
public ShipMap getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@@ -9,7 +9,9 @@ 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;
|
||||
@@ -35,6 +37,7 @@ public class ServerGameLogic implements ClientInterpreter {
|
||||
private final BattleshipConfig config;
|
||||
private final List<Player> players = new ArrayList<>(2);
|
||||
private final Set<Player> readyPlayers = new HashSet<>();
|
||||
private Set<Integer> playersFinishedShellAnimation = new HashSet<>();
|
||||
private final ServerSender serverSender;
|
||||
private Player activePlayer;
|
||||
private ServerState state = ServerState.WAIT;
|
||||
@@ -168,11 +171,19 @@ public class ServerGameLogic implements ClientInterpreter {
|
||||
* @param ships the list of ships placed by the player
|
||||
*/
|
||||
void playerReady(Player player, List<Battleship> ships) {
|
||||
// Überprüfe, ob die Karte des Spielers gültig ist
|
||||
if (!player.getMap().isValid2(ships)) {
|
||||
LOGGER.log(Level.ERROR, "Invalid map configuration for player {0}", player); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
if (!readyPlayers.add(player)) {
|
||||
LOGGER.log(Level.ERROR, "{0} was already ready", player); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
ships.forEach(player.getMap()::add);
|
||||
|
||||
if (readyPlayers.size() == 2) {
|
||||
for (Player p : players)
|
||||
send(p, new StartBattleMessage(p == activePlayer));
|
||||
@@ -188,6 +199,11 @@ 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) {
|
||||
@@ -217,4 +233,30 @@ 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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -29,5 +29,8 @@ enum ServerState {
|
||||
/**
|
||||
* The game has ended because all the ships of one player have been destroyed.
|
||||
*/
|
||||
GAME_OVER
|
||||
GAME_OVER,
|
||||
|
||||
//Game stays frozen as long as firing animation is running
|
||||
SHELL_IN_FLIGHT
|
||||
}
|
||||
|
@@ -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,11 @@ 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'");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,5 +25,7 @@ public interface ClientInterpreter {
|
||||
* @param msg the MapMessage to be processed
|
||||
* @param from the connection ID from which the message was received
|
||||
*/
|
||||
void received(MapMessage msg, int from);
|
||||
// TODO
|
||||
void received(ShellAnimationFinishedMessage shellAnimationFinishedMessage, int from);
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
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
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@ package pp.battleship.model;
|
||||
import pp.battleship.notification.GameEvent;
|
||||
import pp.battleship.notification.GameEventBroker;
|
||||
import pp.battleship.notification.ItemAddedEvent;
|
||||
import pp.battleship.notification.ItemRemovedEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -97,7 +98,7 @@ public class ShipMap {
|
||||
*/
|
||||
public void remove(Item item) {
|
||||
items.remove(item);
|
||||
notifyListeners(new ItemAddedEvent(item, this));
|
||||
notifyListeners(new ItemRemovedEvent(item, this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +185,35 @@ public class ShipMap {
|
||||
getShips().filter(s -> s != ship).noneMatch(ship::collidesWith);
|
||||
}
|
||||
|
||||
//ich brauche eine zweite isValid Methode, da in der ServerGameLogic eine Liste von Schiffen und
|
||||
//kein einzelnes übergeben wird. Da ich keinen Bock habe, dort eine for Schleife zu bauen, mache ich
|
||||
//das hier.
|
||||
public boolean isValid2(List<Battleship> ships) {
|
||||
// Überprüfe, ob jedes Schiff innerhalb der Spielfeldgrenzen liegt
|
||||
//istWithinBounds kommt 20 Zeilen weiter unten. Minas gab uns schon Code vor, um das ganze zu lösen.
|
||||
for (Battleship ship : ships) {
|
||||
if (!isShipWithinBounds(ship)) {
|
||||
return false; // Ein Schiff liegt außerhalb der Grenzen
|
||||
}
|
||||
}
|
||||
// Überprüfe, ob sich keine Schiffe überlappen
|
||||
for (int i = 0; i < ships.size(); i++) {
|
||||
Battleship ship1 = ships.get(i);
|
||||
for (int j = i + 1; j < ships.size(); j++) {
|
||||
Battleship ship2 = ships.get(j);
|
||||
if (ship1.collidesWith(ship2)) {
|
||||
return false; // Schiffe überlappen sich
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; // Alle Schiffe sind korrekt platziert
|
||||
}
|
||||
|
||||
private boolean isShipWithinBounds(Battleship ship) {
|
||||
return isValid(ship.getMinX(), ship.getMinY()) &&
|
||||
isValid(ship.getMaxX(), ship.getMaxY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a battleship at the specified coordinates.
|
||||
*
|
||||
|
Reference in New Issue
Block a user